Document, comentariu, eseu, bacalaureat, liceu si facultate
Top documenteAdmitereTesteUtileContact
      
    


 


Ultimele referate adaugate

Adauga referat - poti sa ne ajuti cu un referat?

Politica de confidentialitate



Ultimele referate descarcare de pe site
  CREDITUL IPOTECAR PENTRU INVESTITII IMOBILIARE (economie)
  Comertul cu amanuntul (economie)
  IDENTIFICAREA CRIMINALISTICA (drept)
  Mecanismul motor, Biela, organe mobile proiect (diverse)
  O scrisoare pierduta (romana)
  O scrisoare pierduta (romana)
  Ion DRUTA (romana)
  COMPORTAMENT PROSOCIAL-COMPORTAMENT ANTISOCIAL (psihologie)
  COMPORTAMENT PROSOCIAL-COMPORTAMENT ANTISOCIAL (psihologie)
  Starea civila (geografie)
 

Ultimele referate cautate in site
   domnisoara hus
   legume
    istoria unui galban
   metanol
   recapitulare
   profitul
   caract
   comentariu liric
   radiolocatia
   praslea cel voinic si merele da aur
 
despre:
 
Fisiere UNIX
Colt dreapta
Vizite: ? Nota: ? Ce reprezinta? Intrebari si raspunsuri
 

 

Sistemul de fisiere constituie locul unde se memoreaza pe suport fizic fisierele sistem si cele utilizator. Sistemul de fisiere este caracterizat prin trei aspecte:

- structura ierarhica; i5c19cc
- independenta ridicata fata de hardware;
- o mare flexibilitate.

Structura ierarhica este organizata sub forma unui arbore cu un director radacina (/). Directorul radacina poate contine fisiere, legaturi sau alte directoare, numite subdirectoare. Subdirectoarele sunt noduri in arbore, iar fisierele sunt frunze. Independenta fata de hardware rezulta din faptul ca fisierele sunt privite ca o succesiune de octeti. Flexibilitatea se bazeaza pe posibilitatea de a monta sau demonta, la orice nivel in ierarhia de fisiere, noi structuri arborescente de directoare si fisiere.

Nivelul de sub radacina este tipic, fiind comun tuturor sistemelor de operare compatibile UNIX. In orice sistem Unix, subdirectorul radacina se gasesc urmatoarele subdirectoare: bin, dev, etc, lib, tmp, usr (care la rindul lui contine subdirectoarele: bin, include, lib, user, man) s.a.m.d.

Structura arborescenta a sistemului de fisiere ofera utilizatorului posibilitatea de a crea si gestiona un numar mare de fisiere.

Principalele particularitati ale sistemului de fisiere sunt:

- un fisier frunza poate fi legat la mai multe directoare chiar daca acesta nu se afla la acelasi nivel in arbore;
- fiecare director contine cel putin doua intrari: '.', care refera directorul curent si '..', care refera directorul superior (numit si parinte);
- orice director este legat la nivelul superior printr-o singura legatura aceasta fiind '..'.

Numele unui fisier poate fi de orice lungime (versiunile vechi limitau numele unui fisier la maxim 14 caractere) si poate contine orice caractere, mai putin caracterele slash (/) si caracterul NULL (marcajul de sfirsit de sir).
Caracterul '/' e folosit pe post de separator de nume de fisiere, iar daca se afla pe prima pozitie indica directorul radacina.

Accesul la un fisier se face prin indicarea pozitiei lui in arbore. Pentru aceasta se indica calea spre acel fisier. O secventa de zero sau mai multe nume separate prin '/', optional prefixata de caracterul '/', formeaza un nume de cale.
Calea prcizata din directorul radacina se numeste cale completa, iar calea precizata din directorul curent se numeste cale relativa.




In Unix se deosebesc patru tipuri de fisiere: ordinare, speciale, fisierele pipe si directoare. Din punct de vedere al sistemului de operare un fisier este un sir de octeti de lungime nedefinita terminat cu caracterul special de sfirsit de fisier (EOF). Citirea sau scrierea incepe de la o locatie de octet specificata prin pointerul de fisier (sau marker), care poate fi pozitionat oriunde in fisier.

Un fisier ordinar este creat de un proces. El poate contine o sursa
(text) sau un fisier executabil (binar). Doua sau mai multe procese pot sa citeasca si sa scrie concurent acelasi fisier. Rezultatul depinde de ordinea in care cererile individuale de I/E apar si este in general imprevizibil.
Informatiile despre un fisier se pastreaza intr-o structura de date numita i-node. Acesta nu contine insa numele fisierului si nici octeti de date ai fisierului.

Fisierele speciale sunt fisiere atasate dispozitivelor de I/E. In directorul /dev se gasesc toate referintele la dispozitivele de I/E: discuri, benzi magnetice, terminale, imprimante, mouse etc. Acestea sunt considerate fisiere speciale. De exemplu, pentru fiecare partitie a unui hard disc se gaseste cite un fisier special. Un fisier special are un i-node, care insa nu refera un bloc de date pe disc. In schimb, acest i-node contine un numar de dispozitiv, care este folosit ca index intr-o tabela de proceduri, din nucleu, pentru dispozitive periferice. Pentru identificarea fiecarui dispozitiv se folosesc doua numere: minor (identifica numarul dispozitivului de tipul dat) si major (identifica tipul dispozitivului).

Exista doua tipuri de dispozitive pentru fisiere speciale: in mod bloc si in mod caracter. Cele in mod bloc contin un vector de blocuri de dimensiune fixa, iar tampoanele nucleu sunt folosite ca si cache pentru cresterea vitezei operatiilor de I/E. Cele in mod caracter realizeaza operatiile de I/E la nivel de caracter sau la nivel de pista.

Acelasi dispozitiv fizic poate detine fisiere speciale atit in mod caracter cit si in mod bloc. Fisierele ordinare si directoarele sunt accesate de sistemul de fisiere printr-un fisier special in mod bloc, pentru a beneficia de avantajele tampoanelor cache. Pe de alta parte, unele aplicatii (baze de date) necesita un acces direct. Multe sisteme Unix folosesc un fisier special in mod caracter care transfera datele direct intre spatiul de adrese al procesului si disc (folosind DMA).

Din punct de vedere utilizator nu exista nici o diferenta intre lucrul cu fisiere ordinare si cele speciale. De exemplu:

$ cp prg.c /usr/acct/k/prg1.c #copiere simpla
$ cp prg.c /dev/lp0 #listare la imprimanta

Fisierele pipe si fisierele FIFO vor fi tratate pe larg intr-un laborator urmator.

Un fisier face legatura intre numele fisierelor si i-node. El nu contine efectiv fisierele care ii apartin ci doar referintele la acestea, sub forma unei succesiuni neordonate de intrari. Orice intrare director este formata din numele fisierului si un numar de identificare. Acesta din urma refera un nod de identificare, i-node, in care sunt pastrate informatiile referitoare la fisierul in cauza.

Fiecare fisier are un singur i-node care contine:

1. Proprietarul fisierului si drepturile de acces ale celorlalti utilizatori.
Superuser-ul ignora drepturile indicate in acest cimp.
2. Tipul fisierului.
3. Drepturile de acces la nivel de utilizator, grup si altii.
4. Timpul ultimului acces si ultimei modificari, data si ora ultimei modificari efectuate asupra i-node-ului.
5. Numarul de legaturi sau contorul de legaturi.
6. Adresele disc ale sectoarelor ce contin datele fisierului.
7. Lungimea fisierului in octeti.

Directorul este pastrat ca un fisier ordinar, dar este marcat ca director in i-node. Un fisier director poate fi citit ca orice fisier, dar nu poate fi scris in mod direct, ci numai prin intermediul anumitor programe.

O pereche (nume_fisier, i-node) este numita in Unix legatura. In Unix este posibil ca doua legaturi, din acelasi director sau din directoare diferite, sa refere acelasi i-node. Aceasta inseamna ca un fisier poate fi identificat sub mai multe nume (fara a exista ambiguitate). Daca i-node-ul este 0, intrarea respectiva este vida, adica legatura a fost stearsa.

Pentru legarea la orice director a unui fisier dintr-un director se poate folosi comanda ln (link). Sintaxa ei este:

ln <nume_cale_veche> <nume_cale_noua>

Comanda este identica cu functia de sistem link. Stergerea unei legaturi se poate realiza prin comanda sau apelul de sistem unlink. La stergerea unei legaturi dintr-un director i-node-ul si blocurile de date asociate nu sunt disponibilizate caci s-ar putea sa mai existe un alt fisier care sa refere acelasi i-node. Din acest motiv i-node-ul contine in structura sa un cimp numit contorul de legaturi. Stergerea unei legaturi implica decrementarea contorului de legaturi
Cind acesta ajunge la 0 nucleul elibereaza i-node-ul si blocurile de date aferente fisierului.

Legarea directoarelor este posibila, dar numai de catre superuser.

O alta caracteristica a sistemului Unix este posibilitatea de a monta un intreg arbore de fisiere undeva in structura altui sistem de fisiere.
Nucleul sistemului de operare Unix recunoaste un singur director radacina. Dar este posibil ca fisierele sa se gaseasca pe mai multe suporturi fizice sau logice, fiecare volum avind un sistem de fisiere propriu. Este posibila suprapunerea radacinii unui astfel de sistem de fisiere pe un director al sistemului de fisiere recunoscut de nucleu. Aceasta operatie se numeste montare si poate fi realizata de superuser prin comanda mount. Directorul la care se face montarea
(trebuie sa fie gol) este numit punct de montare. Daca montarea nu mai este necesara se recomanda demontarea si eliberarea punctului de montare prin comanda umount.

Operatii de I/E

Un proces poate accesa un fisier prin descriptorul de fisier. La crearea sau deschiderea unui fisier nucleul intoarce prin functiile de sistem folosite descriptorul atasat fisierului.
Prin conventie, shell-ul deschide automat la executia unui program trei descriptori pentru: standardul de intrare (0), standardul de iesire (1) si standardul de erori(2).
Operatiile de I/E fara tampon sunt realizate prin functiile open, read,
write, lseek si close. Toate acestea au ca prim argument descriptorul de fisier.
Functiile standard de I/E furnizeaza o interfata cu tampon deasupra functiilor de I/E fara tampon. Programele ce folosesc aceste functii includ fisierul antet stdio.h, deoarece acesta contine prototipul functiilor standard de I/E.

Redirectarea fisierelor standard. Conectarea programelor prin pipe

La deschiderea fiecarei sesiuni utilizator shell-ul deschide in mod automat cele trei trei fisiere: fisierul standard de intrare, fisiereul standard de iesire si fisierul standard de afisare a erorilor si sint atribuite terminalului la care s-a deschis sesiunea respectiva. Daca se executa o comanda, procesul fiu creat de shell mosteneste fisierele deschise, inclusiv cele standard.
Este posibila redirectarea fisierelor standard de I/E catre alte dispozitive periferice sau fisiere: a) operatorii ">" si ">>" redirecteaza fisierul standard de iesire.
Exemple: a1) $ls -1 > fis1 si a2) $ls -1 >> fis1

comanda a1) determina listarea directorului curent in fisierul fis1 (stergind continutul anterior al acestuia), in timp ce comanda a2) determina adaugarea continutului directorului la sfirsitul lui fis1. b) operatorul "<" redirecteaza fisierul standard de intrare. Exemplu
$ mail user1 < letter

realizeaza trimiterea catre utilizatorul user1 a unui mesaj citit din fisierul letter si nu de la tastatura.
Pe linga facilitatile de indirectare/redirectare, shell-ul ofera si posibilitatea conectarii iesirii unei comenzi la intrarea alteia. Aceasta operatie se realizeaza prin intermediul mecanismului de pipe. La nivelul liniei de comanda pipe-ul shell-ului este marcat prin caracterul "|".
De exemplu linia de comanda:

$ who | lpr

solicita executia comenzii who in mod concurent cu comanda lpr, iesirea lui
who fiind conectata direct la intrarea programului lpr. Astfel, acesta pereche de comenzi va lista numele utilizatorilor conectati la sistem pe imprimanta si nu pe ecranul videoterminalului. La prima vedere, efectul este acelasi cu situatia in care s-ar fi introdus comenzile:

$ who > fisier_temporar
$ lpr < fisier_temporar
$ rm fisier_temporar

Intre cele doua solutii exista insa urmatoarele diferente majore:
-in cazul pipe-ului comenzile sint lansate in executie simultan, in timp ce in al doilea caz comenzile se executa strict secvential;
-executia prin pipe este sincronizata de catre nucleul sistemului de operare;
-in cel de-al doilea caz se utilizeaza un fisier temporar care trebuie controlat de catre utilizator (acesta trebuie sa aiba drepturi de acces cores punzatoare pentru a se putea executa comenzile fara erori).
Secventa de instructiuni care simuleaza pipe-ul shell din exemplul de mai sus este urmatoarea:

int pa2i, status, child1, child2; pipe(p); if (child = fork()) == 0) A close(1); dup(pa1i); close(pa1i); close(pa0i); exec1("/bin/who", "/bin/who", 0);
S if (child2 = fork()) == 0) A close(0); dup(pa0i); close(pa0i); close(pa1i); exec1("/bin/lpr", "/bin/lpr", 0);
S
while ((child2 != wait (&status))); exit (status);

Shell-ul ca limbaj de programare

Pina in acest moment, s-a presupus ca toate comenzile prezentate sint introduse de utilizator de la tastatura si sint apoi direct executate. Astfel, limbajul de comanda SHELL a fost privit ca un limbaj control al lucrarilor
(job control language) care permite utilizatorului sa precizeze actiuni si mediul in care ele vor fi executate. Shell-ul se poate folosi de asemenea si ca limbaj de programare, secventele de comenzi putind fi grupate in programe numite proceduri shell. Programele shell pot lucra cu notiuni caracteristice limbajelor de nivel inalt cum ar fi variabila, subrutina, parametri, structuri de control si operatii caracteristice macroprocesoarelor.

Variabila shell

O variabila shell se defineste printr-un nume, care poate avea ca va loare un sir de caractere, atribuit cu semnul egal "=", precum urmeaza

variabila = valoare

Referirea unei variabile se face prin includerea inaintea numelui ei a caracterului "$" -situatie in care se realizeaza efectiv substitutia variabilei prin valoarea sa. Exemplu:

atribuire : $ pozit = /usr/ion utilizare : $ cd $pozit

Variabilele shell pot fi: a) Variabile modificate dinamic de interpretor
Aceste variabile au o semnificatie prestabilita si sint actualizate in mod automat de catre interpretor. Incercarea de modificare a acestora de catre utilizator este ignorata.
$# numarul de parametri ai unei proceduri shell;
$? codul de revenire al ultimei comenzi executate;
$$ identificetorul de proces asociat shell-ului;
$! identificatorul ultimului proces lansat in background;
$- optiunile cu care a fost lansat shell-ul;
$n parametrii transmisi procedurilor shell pe linia de comanda
(numarul n poate lua valori in intervalul 1..9) b) Variabile atribuite la intrarea in sesiune
Aceste variabile sint initializate de catre shell la deschiderea unei sesiuni utilizator cu valorile precizate in fisierele /etc/environment,
/etc/profile si $HOME/.profile, constituind mediul (environment) in care se vor executa toate comenzile lansate ulterior.

$HOME se refera la directorul alocat utilizatorului la intrarea in sesiune (argument implicit al comenzii cd);
$PATH defineste lista directorilor ce sint parcursi de interpretor in cautarea fisierului executabil corespunzator comenzii introduse; (de exemplu:
./; /usr/bin care indica parcurgerea in ordine a directorului curent, apoi a directorului /bin si /usr/bin);
$PS1 defineste prompter-ul asociat interpretorului (implicit $ pentru utilizatorul obisnuit si # pentru superuser)
$PS2 stabileste al doilea prompter (de continuare a liniei de comanda, vezi shell-ul ca limbaj de programare) al interpretorului (implicit >).
$LOGNAME contine numele de conectare al utilizatorului si est pozitionat automat de catre sistem .
$MAIL contine numele directorului in care este plasata posta. Aceasta variabila este folosita de catre shell pentru a anunta utilizatorul despre momentul cand se adauga o informatie noua in acest director.
$SHELL contine numele programului shell folosit de catre editorul de texte vi si de alte comenzi interactive, pentru a determina shell-ul ce va fi executat (sh, csh sau ksh) atunci cand se introduce o comanda de trecere imediata a controlului catre shell.
$TERM este folosita de vi si de alte programe orientate pe ecran pentru a obtine informatii despre tipul de terminal care se foloseste. Aceasta informatie este necesara pentru a permite programelor sa-si ajusteze iesirea conform posibilitatilor terminalului.
Pentru a afisa valoarea unei variabile se foloseste comanda echo, de exemplu linia de comanda care urmeaza afiseaza valoarea variabilei PATH :

$echo $PATH
/bin:/home/ion/bin:/var/adauga/bin:

Valoarea variabilei HOME se poate folosi in comenzi ca de exemplu:

$mv raport $HOME/Docum

pentru a evita introducerea in intregime a numelui de cale pentru directorul destinatie.

Procedura shell

O procedura shell este o colectie de comenzi sau instructiuni ale limbajului de comanda shell ce pot fi preluate dintr-un fisier text sau de la tastatura.
Ea poate fi lansata in executie in orice moment, in doua moduri :

a) $sh fis1

sau b) $chmod fis1 a+x

$fis1

unde fis1 este un fisier text.

Procedurile shell pot contine parametri, interpretati pozitional, pentru care sunt substituite valorile reale la momentul executiei. In interiorul unei proceduri, parametrii de la lina de comanda sunt referiti prin simbolurile $1, ... $9 si sunt substituiti pozitional dupa cum urmeaza :
$1 reprezinta primul parametru de pe linia de comanda (primul cuvant care apare dupa numele comanzii), $2 al doilea parametru s.a.m.d.
Numele comenzii poate fi accesat prin intermediul parametrului $0. O procedura poate fi apelata cu mai mult de noua argumente in linia de comanda, argumentele suplimentare putand fi accesate prin folosirea comenzii interne 'shift'.
In urma executiei acestei comenzi continutul variabilei $n se copie in variabila $n-1.

Pentru exemplificare se presupune ca se doreste un listing cu toti utilizatorii conectati la un anumit tip de terminal si nu pentru orice tip posibil, deoa- rece sirul de caractere 'tty' este in mod permanent inclus in definire.
Procedura foloseste comanda 'grep' care este de tip filtru.

Un filtru este o comanda care are urmatoarea schema de lucru : a) citeste un fisier; b) prelucreaza acel fisier intr-un anumit fel; c) tipareste rezultatul prelucrarii.

Comanda 'grep' extrage dintr-un fisier acele linii care contin o configuratie predeterminata de caractere.

Procedura va contine o singura linie :

who | grep tty

si se poate lansa in executie prin :

$sh whotty

Rezultatul obtinut poate fi de forma:

petre tty2 mar 15 11:43

Procedura 'whotty' se poate generaliza, utilizand un parametru pe linia de comanda, care reprezinta tipul terminalului. Ca de exemplu in procedura
'whoterm' :

who | grep $1

Astfel secventa :

$sh whoterm tty

va afisa :

petre tty2 mar 15 11:43

exact acelasi rezultat ca si 'whotty', intrucat $1 va fi substituit, la executie, prin sirul de caractere "tty". Se poate folosi, deci, aceiasi procedura pentru afisarea numelor utilizatorilor conectati la orice tip de terminal.

Fisierul ".profile" .

Acest fisier al carui continut este constituit din comenzi sau instructiuni catre shell, permite configurarea mediului de lucru propriu al unui utilizator si este citit si executat de catre shell la fiecare deschidere a unei sesiuni utilizator. De exemplu, daca in fisierul ".profile" exista liniile urmatoare, atunci terminalul cu care se lucreaza este de tip 'vt100', si la fiecare conectare se va starta executia programului 'calendar' :

TERM=vt100 export TERM calendar

Daca se doreste vizualizarea pe ecran a continutului acestui fisier, se va putea folosi, de exemplu, comanda :

$cat .profile

Numele acestui fisier incepe cu "." pentru a nu fi listat decat la apelul comenzii 'ls' cu parametrul '-a', un utilizator neavizat nefiind astfel constient de existenta acestuia.

Fisierele '/etc/environment' si '/etc/profile'.

Ansamblul de variabile si valori care sunt furnizate unui program constituie mediul (environment-ul) programului. Variabilele de mediu sunt mostenite de catre procesele utilizator de la shell-ul care le-a lansat. Acesta adauga la propriile variabile de mediu (pe care la randul sau le-a mostenit de la procesul 'init' si care au fost citite de catre acesta din fisierul
'/etc/environment') variabilele citite din fisierele '/etc/profile' si
'$HOME/.profile'. Fisierele '/etc/environment' si '/etc/profile', spre deose bire de '$HOME/.profile' contin informatii valabile pentru toate procesele lansate de catre shell.

Afisarea variabilelor de mediu curente se poate face cu comanda 'env' :

$env
HOME=/home/students/pr1993/cs930764
PWD=/etc/locks/bin/vtu
MAILRC=/home/students/pr1993/cs930764/mailrc
SHELL=/bin/bash
MAIL=/var/spool/mail/cs930764
LOGNAME=cs930764
PS1=:
PS2=...
TERM=vt100
PATH=/usr/bin:/bin:/usr/lpp/vdi/bin/nkc:

Exportul variabilei.

Mediul unei comenzi este reprezentat de valorile variabilelor shell care sunt cunoscute de acea comanda.

Valorile variabilelor de mediu pozitionate de catre shell nu sunt mostenite in mod explicit de catre procesele lansate de acesta. Pentru ca un proces sa poata folosi o valoare a unei variabile de mediu, atribuirea acesteia trebuie sa se faca pe linia de comanda (de obicei inaintea numelui comenzii) sau in interiorul programului. Sa presupunem, de exemplu, ca fisierul de comenzi
'biluta' contine instructiunea :

echo $term

In acest caz, secventa de comenzi :

$term=vt100
$bubu

nu va afisa nimic, deoarece variabila 'term' nu este cunoscuta in fisierul
'bubu' in mod implicit. Pentru ca programul sa afiseze sirul de caractere
"vt100", este necesar fie ca atribuirea sa se faca in fisierul 'bubu', inaintea instructiunii 'echo', fie la linia de comanda ca in exemplu :

$term=vt100 bubu

Aceste atribuiri sunt valabile numai pe durata executiei comenzii. Pentru a face cunoscute valorile variabilelor de mediu asociate unui anumit proces in afara acestuia (tuturor proceselor lansate in acelasi shell) se foloseste comanda interna 'export'. Astfel, daca se doreste ca valoarea variabilei
'term' sa fie utilizata cu valoarea pozitionata in interiorul fisierului
'biluta' si de catre alte programe, se folosesc instructiunile :

term=vt100 export term

Instructiunea 'export' este apelata in fisierele '/etc/profile' si '.profile' pentru a face cunoscute tuturor programelor anumite variabile de mediu ale shell-ului ce au o importantza deosebita cum ar fi : PATH, HOME, TERM etc.

Executie conditionata.

Modul de terminare a executiei unei comenzi este memorat de shell intr-o vari abila interna numita 'exit status' (stare de iesire). Valoarea sa poate fi testata de utilizator pentru a determina modul in care s-a incheiat executia ultimei comenzi (zero -succes, diferit de zero -eroare). Shell-ul poate apoi utiliza 'exit status' pentru a decide asupra actiunii urmatoare.

Interpretorul prevede trei constructii de baza pentru executia conditionata : constructiile 'if', 'while' si 'until'.

Constructia 'if' exista in doua forme :

if ... then

si

if ... then ... else

precum este iustrat in urmatarele doua situatii :

if lista_de_comenzi then lista_de_comenzi fi

si

if lista_de_comenzi then lista_de_comenzi else lista_de_comenzi fi

In constructia 'if' se verifica intotdeauna doar succesul ultimei comenzi din lista deoarece shell-ul tine evidenta doar a unui singur indicator de tip
'exit status'. Cuvantul cheie 'fi' este utilizat pentru a indica sfarsitul listei de comenzi pentru executia conditionata.
Constructia while permite repetarea unui sir de comenzi atit timp cit comenzile din cadrul conditiei nu se executa cu succes. Sintaxa structurii este:

until lista_de_comenzi do lista_de_comenzi done

Sa presupunem ca trebuie scris un program shell care asteapta pina cind este creat un anumit fisier. O metoda ar fi sa se utilizeze structura while:

while test! -r procedure; do sleep 1; done

O alta metoda foloseste structura until:

until test -r procedure; do sleep 1; done

Interpretorul de comenzi contine, de asemenea, doua comenzi interne numite true si false, care returneaza respectiv o stare de iesire zero si unu.
Acestea pot fi folosite, de exemplu pentru realizarea unor bucle infinite, ca mai jos:

while true do date; sleep 60; done

Shell-ul de tip Bourne are doi operatori conditionali:

-operatorul dublu ampersand"&&".

Cind doua comenzi sint separate printr-un dublu ampersand, a doua comanda se va executa doar daca prima comanda reintoarce starea de iesire zero. Astfel comanda

$ test -d /usr/kc&&echo succes!

va tipari mesajul succes! daca fisierul /usr/kc este un director (-d).
Comanda interna test este folosita pentru a testa diferite conditii.

-operatorul bara dubla "||".

Daca doua comenzi sint separate prin aceste 2 bare, se va executa a doua comanda daca prima comanda reintoarce o stare de iesire (exit status) nonzero.
Astfel comanda:

$ test -d /usr/kc || echo eroare!

va tipari mesajul eroare!, daca fisierul nu exista sau daca el exista dar nu este fisier director.

Concluzii la limbajul de comanda al Shellului

In proiectarea unei aplicatii nu foarte complexe, utilizatorul poate opta pentru limbajul de comanda al shell-ului in locul unui limbaj de nivel inalt
(C,FORTRAN,PASCAL,etc.).In alegerea solutiei trebuie sa fie luate in considerare urmatoarele aspecte:
Atunci cind viteza de executie a unui program este importanta vor trebui folosite limbaje mai eficiente decit cel al shell-ului, deoarece folosirea acestuia din urma duce la scaderea vitezei de executie.
O situatie in care se foloseste shell-ul ca limbaj de programare este atunci cind solutia problemei implica o multime de operatii care sint comenzi sistem standard pentru UNIX (cautarea intr-un fisier, sortarea si transformarea fisierelor, crearea si mutarea fisierelor etc.).
Un alt criteriu de decizie consta in tipul datelor de baza implicate in problema. Daca datele de prelucrat sint reprezentate de linii de text sau fisiere text, atunci shell-ul poate reprezenta o buna solutie.

Caracteristici ANSI C

Toate exemplele descrise in continuare sunt scrise in limbajul C care respecta standardul ANSI C.

Prototipul si interfata unei functii

Fisierul antet unistd.h contine prototipul multor functii oferite de sistemul Unix. Prototipul unei functii specifica tipul parametrilor de apel si tipul valorii returnate de functie. Exemple de prototip de functii sunt:

pid_t getpid( void); ssize_t read( int, void *, size_t); void *malloc( size_t);

In primul caz functia getpid nu are argumente si returneaza o valoare de tipul pid_t. In al doilea caz functia read are trei argumente de tipuri diferite: int, un pointer la tipul void si size_t. Valoarea returnata de functie este de tipul ssize_t. In ultimul caz, functia malloc are un singur argument de tipul size_t si valoarea returnata este un pointer la tipul void.
Interfata functiei precizeaza pe linga prototip si fisierele care trebuie incluse in programul care apeleaza aceste functii.

In versiunile anterioare de UNIX nu era definit tipul void motiv pentru care prototipul acestor functii folosea in loc de void tipul int iar in loc de void * tipul char *. Introducerea tipului void permite eliminarea castului.
De exemplu valoarea returnata de functia malloc trebuia prefixata cu un cast explicit la tipul pointerului dorit, deoarece ea returna un pointer la tipul char. Noul prototip al functiei malloc permite apelul sub forma:

int *p; p=malloc( 77 * sizeof( int));

Compilatorul folosit, gcc sau cc, respecta standardul ANSI C.

In versiunile anterioare de UNIX nu erau definite tipurile pid_t, ssize_t si size_t folosite in exemplele anterior prezentate. Aceste tipuri de date si in general toate tipurile terminate cu _t sunt definite ca tipuri primitive de sistem in fisierul antet sys/types.h

Cele doua fisiere antet unistd.h si sys/types.h au rolul de a preveni programele sa foloseasca tipuri specifice de date. Astfel, fiecare implementare alege acele date care sunt impuse de un anumit sistem.

De exemplu, daca se doreste gasirea identificatorului de proces, se aloca o variabila de tip pid_t pentru a memora valoarea returnata de functia getpid. Definitia acestui tip poate sa difere de la o implementare la alt, dar ea se reduce la inlocuirea unui singur fisier (care se include) si aplicatia poate fi recompilata.

Timpul in UNIX

Exista doua timpuri diferite pastrate de sistemul UNIX. Primul este timpul calendar. Acesta valoare precizeaza numarul de secunde scurse de la
1 ianuarie 1970, ora 00:00:00 (Timpul Universal). Acest timp serveste la stabilirea timpului ultimei modificari efectuate asupra unui fisier. Al doilea este timpul de proces. Acestea este numit timp CPU si masoara timpul cit procesul foloseste resursa CPU. Timpul de proces este masurat in tacti (de regula 100 tacti pe secunda). Acest timp este pastrat intr-o variabila de tip clock_t, spre deosebire de primul care este pastrat intr-o variabila de tipul time_t. Standardul POSIX defineste constanta CLK_TCK pentru a specifica numarul de tacti pe secunda.

La masurarea timpului de executie a unui proces, UNIX-ul pastreaza trei valori:

- timpul real consumat;
- timpul CPU consumat in mod utilizator;
- timpul CPU consumat in mod nucleu.

Timpul real consumat este timpul cit procesul se executa. Acesta depinde de incarcarea sistemului, adica de numarul proceselor care se executa in sistem.

Timpul CPU consumat in mod utilizator este timpul scurs pentru executia instructiunilor utilizatorului.

Timpul CPU consumat in mod nucleu este timpul scurs pentru executia functiilor de sistem aferente procesului (de exemplu, timpul scurs pentru rezolvarea unui apel read de catre nucleu).

Pentru a masura acesti timpi se poate executa executa comanda time, care va avea ca argument comanda pentru care se doreste a fi efectuata masuratoarea. De exemplu, pentru a masura timpul scurs intr-o operatie de cautare a secventei "_POSIX_" in toate fisierele dintr-un director se poate folosi:

$cd /usr/include
$time grep _POSIX_ */*.h > dev/null

Iesirea acestui program depinde de interpretorul folosit.

Semnale

Semnalul este un mecanism de sincronizare important in sistem prin care un proces este informat asupra aparitiei unui eveniment. Semnalul poate proveni de la nucleu, de la un alt proces, chiar de la acelasi proces si de la utilizator. Un exemplu de semnal provenit de la nucleu este semnalul SIGSEGV transmis procesului care incearca un acces la memorie in afara propriului spatiu de adrese. Un proces poate trimite la alt proces un semnal de terminare

(SIGTERM) generat la apasarea combinatiei de taste Ctrl-C. Exista o gama variata de semnale, numarul lor depinzind de versiunea de UNIX folosita. De regula numarul lor este intre 12 si 32. La primirea unui semnal, un proces are trei alternative:

a. sa ignore semnalul, lucru nerecomandat in cazul semnalelor ce indica erori hardware (de exemplu impartirea cu 0); b. sa execute actiunea implicita atasata semnalului (de exemplu pentru impartirea cu 0 actiunea implicita este terminarea); c. sa execute o rutina (functie) de tratare a semnalului.

Nu se poate opta pentru oricare dintre alternative pentru orice semnal.

Comunicarea intre procese

Comunicarea intre procese (IPC=Inter Proces Comunication) se poate realiza in diverse moduri: semnale, fisiere, pipe, pipe cu nume, semafoare, mesaje, memorie partajata, socket si stream. Tipurile de comunicatie folosite actualmente mai des si permise de diverse versiuni de UNIX sunt ilustrate in tabelul 1. Primele cinci metode sunt folosite de procese aflate pe acelasi host, iar ultimele doua metode sunt folosite de procese aflate si pe host-uri diferite.

--------------------------------------------------------------------- | Tipuri de comunicare | V7 | SVR | 2SVR3.2 | SVR4 | 4.3BSD | 4.3+BSD |
--------------------------------------------------------------------- | pipe | * | * | * | * | * | * |
| FIFO | | * | * | * | | * |
----------------------------------------------------------------------
| cozi de mesaje | | * | * | * | | |
| semafoare | | * | * | * | | |
| memorie partajata | | * | * | * | | |
--------------------------------------------------------------------- | socket | | | | * | * | * |
| stream-uri | | | * | * | | |
--------------------------------------------------------------------- Tabelul 1 - metode de comunicare folosite in UNIX

Semnalele sunt folosite de procese pentru a informa alte procese. Din pacate semnalele nu contin suficienta informatie, deseori necesara in aplicatii.
Un semnal este un eveniment asincron, care intrerupe procesul care-l receptioneaza, programarea in aceste cazuri fiind mai complexa. Semnalele sunt, de regula, folosite pentru terminarea unui proces.

Prin trasarea procesului, un proces parinte poate controla executia unui proces fiu. Doarece procesul tata poate citi si scrie datele procesului fiu, cele doua procese pot comunica liber. Trasarea proceselor este folosita numai in depanatoare, doearece este complicata si nesigura pentru uz general.
In general se prefera comunicarea prin pipe intre doua procese in relatia parinte fiu.

Comunicarea printr-un fisier este o metoda simpla prin care procesele pot schimba date. De exemplu, un proces ce executa editorul ed poate scrie intr-un fisier, iar alt proces ce executa utilitarul nroff poate sa-l formateze.
Folosirea fisierelor pentru comunicare are in principal doua dezavantaje:

a. daca cele doua procese lucreaza concurent, nu exista sincronizare corecta intre procese (procesul cititor poate conchide din detectarea unui sfirsit de fisier gresit, terminarea comunicarii); b. daca comunicarea este de durata, dimensiunea fisierului creste considerabil.

Folosirea unui fisier gol pe post de semafor este o tehnica des folosita in UNIX.

Pipe rezolva problema de sincronizare a fisierelor. Cu toate ca are un i-node atasat, nu exista referinta la el. Citirea si scrierea unui pipe este asemanatoare cu citirea si scrierea unui fisier, dar exista diferente majore.
Dimensiunea maxima a unui pipe este fixa, valoarea pe care nu se poate scrie, iar dintr-un pipe gol nu se poate citi. Un octet citit nu se poate reciti, deci datele vehiculate prin pipe nu sunt pastrate. Pipe poate fi folosit si in linia de comanda (de exemplu ls | more). Comunicarea prin pipe are trei dezavantaje majore:

a. procesele care comunica trebuie sa fie in relatia parinte fiu sau cu stramos comun (inconvenient major cind, spre exemplu, unul dintre procese este gestionarul unei baze de date, iar celalalt o aplicatie care gestioneaza baza); b. versiunile mai vechi nu ofera citire si scriere atomica pentru pipe cu mai multe procese ce scriu si citesc (acelasi proces gestionar al bazei de date si mai multi clienti care lanseaza cereri); c. operatii lente, cu toate ca nu se fac operatii de I/E, copierea user-kernel si invers pot fi critice pentru unele aplicatii.

Pipe cu nume, numite si FIFO au aparut odata cu versiunea III pentru a elimina primele doua neajunsuri. Un fisier FIFO se comporta ca un fisier pipe si orice proces, daca are drepturi poate sa-l acceseze. Atomicitatea operatiilor este asigurata. Singurul dezavantaj ramine viteza, mult prea lenta pentru unele aplicatii.

Semaforul este un fanion care previne doua sau mai multe procese sa acceseze simultan aceasi resursa.

Mesajul este un pachet mic de date, ce poate fi trimis intr-o coada de masaje. Mesajele pot fi de diferite tipuri. Orice proces, daca are drepturile necesare, poate primi un mesaj din coada. Mesajul poate fi ales: fie primul, fie primul de un anumit tip, fie primul dintr-un anumit grup de tipuri.

Memoria partajata este mijlocul de comunicatie cel mai rapid. Principiul este simplu: acelasi spatiu de memorie este mapat in spatiul de adrese a doua sau mai multe procese. Cit de repede datele sunt scrise in memoria partajata, atit de repede pot fi disponibile procesului cititor. Un semafor sau mesaj este utilizat pentru a sincroniza procesul care scrie in raport cu cel care citeste.

Gestionarea erorilor

La aparitia unei erori la apelul unei functii UNIX se returneaza deseori valoarea (-1) si varianbila globala errno ofera o valoare ce contine informatii suplimentare despre eroare. Aceasta nu este insa o conventie generala pentru ca exista functii care intorc in caz de eroare un pointer NULL. Fisierul antet errno.h, ce se include in fisierele din directiva #include, defineste variabila errno si valorile constantelor simbolice pe care aceasta variabila le poate lua. De exemplu functia open, in cazul aparitiei unei erori la deschiderea unui fisier asupra caruia nu exista dreptul de scriere, atribuie variabilei errno valoarea EACCES. Valorile de eroare posibile sunt descrise in manuale sistem. Tabelul 2 prezinta diferentele dintre functii.

ÚAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¿
³ Functii ³ strerror(errno) ³ Terminare cu ³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
³ err_sys ³ da ³ exit(1); ³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
³ err_ret ³ da ³ return; ³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
³ err_quit ³ nu ³ exit(1); ³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
³ err_msg ³ nu ³ return; ³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
³ err_dump ³ da ³ abort(); ³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAÙ tabelul 2

Standardul POSIX defineste variabila errno ca:

extern int errno;

Valoarea variabilei errno nu este stearsa de apelul unei functii fara eroare. Daca insa valoarea variabilei nu este testata in cazul unei erori, apelul urmator al unei functii poate suprascrie valoarea variabilei. Valoarea
0 nu poate fi atribuita variabilei errno si nici o constanta simbolica nu are aceasta valoare.

Standardul C defineste doua functii utile pentru afisarea mesajelor de eroare. Prima este strerror cu interfata:

#include <string.h> char *strerror( int nrerr);

care intoarce pointerul la mesajul de eroare.

Aceasta functie realizeaza corespondenta intre nrerr (este de regula valoarea variabilei errno) si mesajul de eroare aferent erorii. A doua functie este perror si are interfata:

#include <stdio.h> void perror( const char *msg);

Functia afiseaza la iesirea standard de erori mesajul msg urmat de caracterul ':', un caracter vid si mesajul aferent valorii din variabila errno.
Functia revine fara a intoarce ceva util. Un exemplu de utilizare a acestei functii este programul:

Ex 1:
/*
A se compila cu:cc p1.c err.o
Program de test a functiilor de eroare
*/
#include <erno.h> include "hdr.h"

int main(int argc,char *argvai)
A int fd=7,no=5; char bufa5i; printf( stderr, "EACCES: %s\n", strerror( EACCES));

errno=ENOENT; perror( argva0i);

if ( read( fd, buf, no) == -1) err_sys("Eroare read"); exit(0);
S
Functia perror primeste ca argument numele programului(argva0i).
Acest lucru este util pentru cazurile in care programul face parte dintr-un lant de pipe-uri, ca in:

p1 < input | p2 | p3 > output

deoarece se poate preciza exact programul care a generat mesajul de eroare.
Rezultatul executiei acestui program este:

$a.out
EACCES: Permission denied a.out: No such file or directory
Eroare read: Bad file number

Pentru a nu apela aceste functii direct si din ratiuni de spatiu(pentru a nu extinde fiecare exemplu cu liniile de tratare a erorilor) toate exemplele vor include la compilare fisierul err.c sau direct fisierul obiect err.o
In acest mod fiecare caz de eroare este tratat de un singur apel al unei functii de tratare a erorii. Exemplul anterior foloseste functia err_sys din programul err.c.
Toate functiile de tratare a erorilor din programul err.c folosesc functii cu lista de argumente de lungime variabila din ANSI C(Kerna88i).
Aceasta facilitate, oferita de ANSI C, difera de varargs oferita de versiunile mai vechi de sistem ca SVR3 si 4.3BSD. Numele de macro sunt identice dar s-au schimbat argumentele de apel.

Conceptul de proces

Procesul este un program in executie. Ca urmere, procesul este dinamic, pe cind programul este static. Pentru un program dat (fisier executabil) pot exista la un moment dat unul sau mai multe procese asociate, numite instante.
Orice proces UNIX, cu exceptia procesului 0, este creat prin apelul functiei de sistem fork. Procesul nou creat se numeste proces fiu, iar procesul care a apelat functia fork se numeste proces parinte.
Programul executabil este incarcat in memorie prin apelul functiei exec. Chiar si atunci cind fiind intr-o sesiune de lucru, se lanseaza o comanda
(care este de fapt un program executabil), shell-ul foloseste functiile de sistem fork si exec pentru executia comenzii date. Lucrurile se petrec pe scurt in felul urmator:

La executia unei comenzi de catre shell aceasta citeste linia de comanda si desparte comanda de argumentele sale. Se apeleaza functia sustem fork in urma careia rezulta cele doua procese: parintele si fiul. Procesul parinte printr-un apel al functiei de sistem wait cedeaza procesorul procesului fiu. Acesta la randul sau printr-un apel al functiei de sistem exec executa un nou program, care este chiar comanda data. Nucleul incarca in zona de memorie a shell-ului noul program si procesul este continuat cu acest program, caruia ii sunt transmise argumentele. In cadrul procesului nu se schimba decit programul, restul ramane nemodificat. La incheierea executiei programului se apeleaza functia sistem exit, care cauzeaza terminarea procesului fiu si iesirea din starea de asteptare a procesului parinte.

Executia unui program utilizator se poate face in doua moduri:in modul utilizator si in modul nucleu (sau sistem) asociate modului de functionare ale procesului.
In modul utilizator procesele au acces numai la propria zona de cod, date si stiva utilizator.
In modul nucleu un proces contine instructiuni privilegiate si poate avea acces la structurile de date ale nucleului. Nucleul, in termeni de proces, nu este un proces separat care se executa in paralel cu procesul utilizator, ci devine o parte integranta a procesului utilizator.
Spatiul virtual de adrese al unui proces este cuprins intre 0 si adresa virtuala maxima accesibila procesului. Acest spatiu este alcatuit din trei segmente:
- segmentul text (cod)
Contine codul. Daca codul este pur, atunci poate fi partajat de alte procese. Este protejat la scriere.

- segmentul de date
Contine datele alocate static sau dinamic de catre proces.

- segmentul de stiva
Contine argumente, variabile locale si alte date pentru executia functiilor in modul utilizator.

Un fisier executabil contine antetul, segmentul text si date (numai cele initializate). Deoarece un proces se poate executa in modul utilizator si nucleu, i se mai asociaza si o stiva nucleu, care va contine informatii necesare pentru functiile sistem. Un proces trece din modul utilizator in cel nucleu cand se apeleaza o functie de sistem sau cand este generata o intrerupere.
Segmentul de date si stivele utilizator si nucleu sunt dinamice, adica dimensiunea lor variaza in timpul executiei.
Asupra segmentului de date, utilizatorul poate interveni prin urmatoarele functii sistem:

Functia malloc
Aloca o zona de memorie de dimensiune ceruta. Intefata sa este:

#include <stdlib.h>

void *malloc( dimensiune);
Intoarce un pointer diferit de 0 in caz de succes, NULL in caz de eroare.
In caz de succes, functia returneaza pointerul la inceputul zonei alocate. In caz de eroare functia returneaza pointerul NULL, iar variabila errno contine codul erorii.

Exemplu de utilizare:

void *ptr; if ((ptr = malloc (10000)) == NULL)A perror( "malloc"); exit(1);
S

Functia calloc

Aloca o zona de memorie contigua de dimensiune nr-element*dim_element
(in octeti) si o initializeaza cu caracterul NULL. Interfata sa este:

#include <stdlib.h>

void *calloc( size_t nr_elem, size_t dim_element);

Intoarce un pointer diferit de 0 in caz de succes, NULL in caz de eroare.
Functia returneaza pointerul in zona alocata. In caz de eroare variabila erno va contine codul erorii.

Exemplu de utilizre:

struct A int s1; long s2; char s3a10i;
S s; void *ptr; if ((ptr = calloc( 10, sizeof(s))) == NULL)A perror ("calloc"); exit(1);
S

Functia realloc
Redimensioneaza o zona de memorie obtinuta prin functia maloc, calloc sau realloc la new_dim. Functia are interfata:

#include <stdlib.h> void *realloc( void *ptr, size_t new_dim);

Intoarce un pointer diferit de zero in caz de succes, NULL in caz de eroare.
Functia returneaza in caz de succes pointerul la zona alocata, care poate fi cel initial sau nu (in cazul alocarii la o alta adresa). In caz de eroare, variabila errno contine codul de eroare.

Exemplu de utilizare:

void *ptr;
/* alocare zona de memorie */ if ((ptr = malloc (10000)) == NULL)A perror ("malloc"); exit(1);
S
/* crearea zonei de memorie alocate mai sus */ if ((ptr = realloc( ptr, 200000) == NULL)A perror( "realloc"); exit(2);
S

Functia free elibereaza o zona de memorie alocata prin malloc, calloc sau realloc.
Interfata functiei este urmatoarea:

include ,stdlib.h>

free( void *ptr)

Revenirea din functie se considera ca o tratare corecta. Dar daca ptr era eronat, rezultatul este imprevizibil.

Exemplu de utilizare:

void *ptr;
/* alocarea unei zone de memorie */ if ((ptr = malloc (10000)) == NULL)A perror( "malloc"); exit(1);
S
/* eliberarea zonei alocate */ free( ptr);

Se mentioneaza faptul ca la segmentul de date poate fi atasata si o zona de memorie comuna, lucru prezentat in cadrul comunicarii intre procese.
Cand un proces invoca un program, el primeste ca parametri argumentele liniei de comanda si mediul program. Recuperarea de catre program a parametrilor de apel (argumente si mediu) se face declarand programul principal astfel:

main( int argc, char *argvai, char *envpai)

Numarul elementelor tabloului de adrese referit de argv este argc.
Adresele parametrilor de apel sunt in tabloul referit de argv.
Adresele variabilelor de mediu sunt in tabloul referit de envp. Afisarea parametrilor de apel si a mediului se poate face astfel:

/* afisarea argumentelor de apel */ for ( k=0; k<argc; ++k) A printf( parametrul nr d este: s\nn", k+1, argvaki;
S;
/*afisarea variabilelor de mediu*/ for ( k=0; ; ++k) A if (envpakia0i) A printf ("variabila de mediu nr\ d este: s\n",k+1, envpaki;
S else break;
S;
Variabilele de mediu sunt citeva siruri de caractere de forma:

NUME = valoare

Unele dintre cele mai uzuale valori care se gasesc in mediul transmis unui program sunt:

HOME - numele de cale al directorului de referinta;
PATH - lista directoarelor in care sunt cautate comenzile;
MAIL - numele fisierului care contine mesajele primite prin mail;
TERM - tipul terminalului;
SHELL - numele de cale al fisierului binar ce contine shell-ul;
LOGNAME - numele sub care este cunoscut utilizatorul in sistem.

Observatii:

a. Mediul program curent poate fi afisat prin comanda env.

b. In programe, variabilele mediului pot fi recuperate nu numai prin argumentul envp mai sus prezentat, ci si prin variabila externa environ, care este un pointer la un tablou de pointeri catre sirurile de caractere care semnifica variabilele mediului.

Exemplu: extern char **environ; main()
A int k;
for (k=0;; ++k) if (environaki)
A printf ("variabila de mediu nr d este:\ s\n", k+1, environaki);
S else break;
-
S

Recuperarea variabilelor de mediu prin envp si environ sunt echivalente.

c. Recuperarea valorii unei variabile de mediu se poate face cu functia getenv care are interfata:

#include <stdlib.h>

char *getenv (const char *nume);

Intoarce un pointer la valoarea variabilei asociate cu nume, NULL in cazul absentei variabilei.

Exemplu:
char *terminal; if (( terminal = getenv("TERM")) == NULL)
A printf ("variabila TERM nu este definita"); exit (1);
S printf ("Terminalul este: s\n", terminal);
-

Identificatori. Identificatorul utilizatorului

Identificatorul utilizatorului, pe scurt ID utilizator, din cimpul al treilea al unei intrari din fisierul /etc/passwd este un numar intreg pozitiv prin care sistemul identifica utilizatorul. Acest numar este atribuit utilizatorului de catre administratorul de sistem, la introducerea unui nou utilizator in sistem. Acest ID este, de regula, unic si nu poate fi modificat.
Utilizatorul cu ID egal cu 0 este numit superuser sau root. Intrarea in fisierul de parole corespunzatoare superuser-ului are pe primul cimp numele root.
Superuser-ul are control total asupra sistemului (din acest motiv se spune ca superuser-ul are drepturi speciale sau privilegiate). Utilizarea anumitor functii este permisa doar superuser-ului.
La intrarea in sistem a unui utilizator, programul login fixeaza acest
ID ca ID utilizator primului proces creat, shell-ul. Toate procesele descendente din acest shell vor mosteni acest ID utilizator. ID-ul utilizatorului este numit si ID-ul utilizatorului real.

Identificatorul grupului

Asemeni ID-ului utilizatorului, ID-ul grupului este atribuit de catre administratorul de sistem, la introducerea unui nou utilizator in sistem. Grupul serveste la reunirea acelor utilizatori care folosesc partajat anumite resurse
(de exemplu fisiere). De exemplu un fisier poate avea drepturile de acces astfel fixate incit doar membrii grupului sa poata avea acces la el. Utilizatorul lucreaza de regula cu numele sau de login si cu numele grupului. Sistemul realizeaza corespondenta de la nume la ID prin fisierul /etc/passwd pentru utilizator, respectiv prin fisierul /etc/group pentru grup. De exemplu comanda:

ls -l

afiseaza numele proprietarului unui fisier folosind fisierul de parole.

ID de grup al utilizatorului care a deschis sesiunea de lucru va fi fixat ca ID de grup pentru procesul shell. Acesta va fi mostenit de toate procesele descendente din shell. ID-ul grupului este numit si ID-ul grupului real.

Identificatori suplimentari de grup

Incepind cu versiunea 4.2BSD un utilizator poate adera la mai multe grupuri (maxim 16). ID-ul grupurilor suplimentare se obtin din fisierul
/etc/group, de unde se identifica primele 16 intrari care au utilizatorul ca membru.

Pentru procese avem :

a. Identificatorul de proces

Este un numar intreg mai mare sau egal cu 0. El este in strinsa corelatie cu intrarea in tabela proceselor. Procesul cu identificatorul 0 este procesul swapper, iar procesul cu identificatorul 1 este procesul init. Intrucit cuvintul identificator apare frecvent, in continuare acesta va fi prescurtat la
ID.

b. ID de proces al parintelui

Acesta este ID-ul procesului care a lansat functia fork.

c. ID grupului de procese (a nu se confunda cu ID-ul grupului de utilizatori)

In UNIX se pot grupa procese legate intre ele. De exemplu, un sistem de gestiune a unei baze de date, poate fi impartit in mai multe procese pentru a obtine o concurenta in efectuarea operatiilor de I/E. Unul din membrii grupului de procese este liderul grupului. Toate procesele din grupul respectiv vor avea ca ID al grupului de procese valoarea ID al procesului lider. Deci, daca un proces are ID egal cu cel al grupului de procese, atunci acel proces va fi lider.
Oricare proces poate iesi din grupul respectiv si sa devina lider, formindu-si un nou grup.

d. Terminalul de control

Este primul terminal deschis de liderul grupului de procese. Normal, terminalul de control pentru procesele unui utilizator este terminalul de la care a fost lansata comanda login. La formarea unui nou grup, procesele membre ale noului grup nu mai au un terminal de control. Cind procesul lider de grup s-a terminat, toate procesele cu acelasi terminal de control primesc semnalul
"hungup".

e. ID utilizatorului real

f. ID grupului real de utilizatori

g. ID utilizatorului efectiv

Acest atribut serveste la determinarea drepturilor de acces la fisiere.
Spre deosebire de acesta, ID-ul utilizatorului real serveste la autentificarea utilizatorului si la comunicatia intre utilizatori. ID-ul utilizatorului efectiv coincide de cele mai multe ori cu ID-ul utilizatorului real, dar citeodata procesul, sau unul din stramosii sai, a setat bitul de setare identificator utilizator. Denumirea acestui bit in engleza este "set user-ID".

h. ID grupului efectiv de utilizatori

Daca bitul 5 din fig 2 este pozitionat, atunci tot ce s-a spus la punctul g, ramine valabil si aici. Denumirea acestui bit in engleza este
"set grup-ID".

0 3 4 5 6 7 8 9 10 11 12 13 14 15
ÚAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¿
³ ³ ³ ³ ³ r³ w³ x³ r³ w³ x³ r³ w³ x³
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAÙ fig 2

biti : 0-3 tipul fisierului
4 bit setare identificator fisier
5 bit setare identificator grup
6 bit setare swapping (sticky bit)
7-9 proprietar
10-12 grup
13-15 restul utilizatorilor

Pozitionarea bitului 4 si 5 se poate face prin apelurile de sistem setuid si setgid. Asupra lor se va reveni.

i. Dimensiunea limita a fisierelor

Atributul acesta exprima dimensiunea maxima a unui fisier creat prin
write. Apelul de sistem ulimit poate returna limita unui fisier sau poate sa o modifice.

j. Dimensiunea limita a segmentului de date

Atributul exprima dimensiunea maxima a segmentului de date al unui proces.

k. Valoarea nice

Aceasta valoare este folosita in calculul prioritatii unui proces. Aceasta valoare este de obicei intre 0 si 39. Cu cit valoarea sa este mai mare, cu atit prioritatea procesului este mai scazuta. Numai procesele superuser pot da valori negative. Valoarea se poate fixa cu functia de sistem nice.

De la crearea unui proces pina la terminarea sa, el trece prin mai multe stari gestionate de nucleu (vezi curs).

Starile unui proces Unix

Cu exceptia procesului 0, toate celelalte procese sunt create prin apelul functiei de sistem fork. Starea "creat" este o stare de pornire.

In urma apelului functiei fork, segmentele parintelui sunt practic dublate, fiind nevoie in acest sens de memorie interna. Daca exista spatiu de memorie interna suficienta, procesul va trece in starea "ready" (gata de executie). In caz contrar va fi trecut in starea "ready suspendat", adica se va gasi in memoria externa (pe dispozitivul swapping). Din starea "ready", planificatorul de procese il va trece in starea "run mod nucleu", unde activitatea functiei fork se va incheia. Trecerea procesului in aceasta stare se va face pe baza de prioritate. Prioritatile sunt dinamice si se calculeaza din secunda in secunda astfel:

prioritate=baza+(utilizare_recenta_CPU)/constanta+valoare_nice

Se mentioneaza faptul ca rutina ceasului, inafara calculului prioritatii, mai are si alte functii:
- activeaza periodic procesul swapper,
- transmite semnalul SIGALRM catre procese;
- masoara timpul sistem;
- reprogrameaza ceasul de timp real al sistemului;
- lanseaza anumite functii ale nucleului in functie de valoarea unor timeri interni;
- calculul unor valori statistice pentru procese etc.

Planificatorul de procese procedeaza conform urmatorului algoritm:

algoritm schedule_proces; input: output: A
while(nici un proces nu este selectat pentru executie)
A
Alege procesul cu prioritatea cea mai mare din coada proceselor in starea ready(in memorie); if(nu exista procese in starea ready)
Procesorul este pus in stare de asteptare;
/*Intreruperea de ceas scoate procesorul din aceasta stare*/
S
Sterge procesul selectat din coada ready;
Schimbare de context pentru procesul selectat;
S

Cind functia de sistem apelata se termina (initial fork), procesorul va fi trecut in starea "run mod utilizator". Din aceasta stare poate reveni in starea "run mod nucleu" daca apare o intrerupere sau procesul apeleaza o functie de sistem.

Cind ceasul emite o interupere catre procesor, procesul care se executa in mod utilizator este trecut in starea "run mod nucleu". Cind handler-ul de ceas
(rutina de tratare a intreruperii de ceas) isi termina activitatea, nucleul poate decide sa fie trecut in starea de executie alt proces. In acest caz procesul analizat va fi trecut in starea "ready preemptat". Deci in starea "ready preemptat" ajung procesele care sunt executate in mod nucleu si trebuie sa revina in mod utilizator, dar este planificat pentru executie alt proces mai prioritar.
Un proces din starea preemptat poate fi swappat. Cind un proces din starea "ready preemptat" este planificat pentru executie, el este trecut direct in starea "run mod utilizator".

Tema :
- realizati exemple de programe cu limbajul de comanda al shellului
- afisati variabilele de mediu cu program
- afisati diversi identificatori in procese tata si fiu


Colt dreapta
Creeaza cont
Comentarii:

Nu ai gasit ce cautai? Crezi ca ceva ne lipseste? Lasa-ti comentariul si incercam sa te ajutam.
Esti satisfacut de calitarea acestui document, eseu, cometariu? Apreciem aprecierile voastre.

Nume (obligatoriu):

Email (obligatoriu, nu va fi publicat):

Site URL (optional):


Comentariile tale: (NO HTML)


Noteaza documentul:
In prezent fisierul este notat cu: ? (media unui numar de ? de note primite).

2345678910

 
Copyright© 2005 - 2024 | Trimite document | Harta site | Adauga in favorite
Colt dreapta