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:
 
Shell-ul Unix
Colt dreapta
Vizite: ? Nota: ? Ce reprezinta? Intrebari si raspunsuri
 

 

Orice utilizator al unui calculator interactioneaza la un moment dat cu shell-ul. Fie ca apare sub forma unor iconite mititele, fie sub forma unui j8v9vg
PROMPT care invita la tastarea unor comenzi, shell-ul este prima interfata pe care un sistem de operare o ofera utilizatorilor sai. In acest laborator ne propunem sa aratam ca shell-ul este un program ca oricare altul si sa aratam cum poate fi construit unul in cazul sistemului de operare Unix.

1. Ce este un shell ?

Cuvintul SHELL inseamna in limba engleza SCOICA sau carapace. Asta este si programul care se numeste shell pentru sistemul de operare: un invelis care imbraca sistemul, primul lucru pe care il vedem dintr-un sistem de operare.
Cele ce urmeaza sunt despre sistemului de operare Unix. Ideile prezentate sunt insa valabile si pentru alte sisteme de operare, desi corespondenta poate sa nu fie evidenta. Ideea centrala este urmatoarea: un nucleu de sistem de operare este o biblioteca de functii, care pune la dispozitia utilizatorului o serie de operatii, numite "apeluri de sistem". Shell-ul este un simplu program care foloseste aceste operatii pentru a oferi o prima interfata cu utilizatorul.

------------------------------------------------------ utilizator
| ^ comenzi| |rezultate
--------v-------|-------- | shell | proces |
| | |
|---v----------------^---|
| \_creaza_proces_/ |
| |
| nucleu |
------------------------- | hardware |
------------------------- -------------------------------------------------------

1.1.Bucla principala

Misiunea unui shell este de a citi de la utilizator comenzi pe care apoi le interpreteaza si le executa. Executarea comenzilor se face folosind apelurile de sistem. Pe scurt, orice shell are structura urmatoare:

------------------------------------------------------ while (1) A
/* 1 */ scrie_prompt();
/* 2 */ linie = citeste_linie_de_la_utilizator();
/* 3 */ comanda = identifica_comanda(linie);
/* 4 */ argumente = identifica_argumente(linie);
/* 5 */ executa_comanda(comanda, argumente);
/* 6 */ asteapta_terminarea_comenzii();
S
-------------------------------------------------------




Apelurile de sistem sunt folosite pentru:

a*i A scrie utilizatorului mesaje (prompt);
a*i a citi tastele apasate de utilizator;
a*i a ruga nucleul sa execute o comanda;
a*i a astepta executarea acesteia sa se termine.

Observam ca shell-ul NU scrie nici un fel de rezultate pe ecran (poate doar cind s-a produs o eroare)! Shell-ul citeste un nume de comanda, pe care o executa ca un proces separat. Acest proces este cel care tipareste rezultatele vazute de utilizator. De exemplu, cind folositi un sistem Unix, o interactiune tipica este:

------------------------------------------------------ Red Hat Linux release 4.2 (Biltmore)
Kernel 2.0.33 on an i586 login: marni
Password:
Last login: Tue Mar 17 21:00:56 from ppp2.tuiasi.ro
You have mail. eureka (marni):I>id uid=529(marni) gid=100(users) eureka (marni):I>ls / cdrom etc lib usr export lost+found var mnt proc bin dev home net sbin devices kernel tmp eureka (marni):I>
------------------------------------------------------
Textul "login:" este scris de programul "getty", care reprezinta procesul de conexiunea a unui user cu un terminal. Textul "Password:" este scris de programul "login", care executa autentificarea. Dupa identificare, se porneste shell-ul. Orice shell are un prompter, unde pot fi tastate comenzile.

2. Cel mai simplu exemplu

Iata probabil cel mai simplu exemplu posibil de shell pentru sistemul Unix, care este pe deplin functional! (Incercati-l!) Shell-urile moderne ofera o paleta de functionalitati suplimentare care fac viata utilizatorului mai simpla, dar la rigoare exemplul din codul de mai jos este perfect suficient, desi nu intotdeauna foarte convenabil de folosit. O virtute incontestabila insa are, si anume simplitatea, lucru care il si face subiectul nostru de studiu.

------------------------------------------------------ /* smallest shell */ a,ba99i,*c,da99i;main()Awhile(printf(">"),c=d,*c=a=gets(b))A for(;*++c=strtok(a," ");a=0);fork()?wait(0):execvp(*d,d+1);SS
-------------------------------------------------------

Puteti compila si executa acest program pe orice platforma Unix care poseda un compilator de C. Daca fisierul se numeste "shell.c", puteti sa o faceti in urmatorul fel:

------------------------------------------------------ $ cc shell.c -o shell
"shell.c", line 2: warning: old-style declaration or incorrect type for: a
"shell.c", line 2: warning: old-style declaration or incorrect type for: b
"shell.c", line 2: warning: old-style declaration or incorrect type for: c
"shell.c", line 2: warning: old-style declaration or incorrect type for: d
$ ./shell
>
-------------------------------------------------------

(Nu trebuie sa va ingrijoreze eventuale WARNING-uri; programul este corect.)

Semnul `> este prompt-ul. Puteti tasta orice comanda:

------------------------------------------------------ >ls / cdrom etc lib usr export lost+found var mnt proc bin dev home net sbin devices kernel tmp
>id uid=529(marni) gid=100(users)
>
-------------------------------------------------------

Puteti tasta CONTROL-d pentru a termina interactiunea cu el.

Sa vedem cum functioneaza acest mic shell.

2.1 Functiile de biblioteca

Inainte de a incerca sa intelegem cum procedeaza, sa analizam fiecare din functiile C folosite. O parte din functii sunt C standard si este oferita de orice compilator (printf(), gets(), strtok()), altele sunt apeluri de sistem
Unix (fork(), execvp(), wait()).

2.2.2 printf()

Prima si cea mai simpla functie folosita este printf(). Ea este folosita pentru a tipari prompt-ul. Aceasta functie este o functie de biblioteca, dar care este implementata la rindul ei in termenii apelului de sistem write(), prin care in Unix se pot trimite date spre un periferic (in acest caz ecranul).

2.3.3 gets()

Functia gets() este opusa lui printf(): este folosita pentru a citi o linie de la utilizator. Argumentul ei este un array de caractere, unde va pune rezultatul citirii (un sir de caractere). Rezultatul apelului functiei este chiar argumentul ei (sau 0 daca s-a intilnit sfirsitul de fisier, ceea ce in cazul utilizatorului in general inseamna ca acesta a apasat CONTROL-d). In plus, gets() schimba sfirsitul de linie (\n) cu un sfirsit de sir (\0). Ca si printf(), gets() se bazeaza pe apelul de sistem read(), care (opusul lui write()), citeste date de la un periferic sau fisier.

2.4.4 strtok()

Functia strtok() este standard C. Declaratia ei se gaseste in headerul
<string.h>. Numele ei inseamna "string tokenize", adica "imparte sir in cuvinte". Functionarea ei este relativ complexa. Ea are doua argumente, ambele siruri de caractere, si intoarce un pointer spre un sir de caractere:

------------------------------------------------------ char *strtok(char * text, const char * separatori);
-------------------------------------------------------

Functionarea ei este speciala daca "text == NULL". Scopul ei este de a imparti sirul "text" in bucatele care sunt despartite de caractere din sirul

"separatori". Ca sa intelegem mai bine, iata intii un exemplu care o foloseste intr-un mod tipic.

------------------------------------------------------ #include <string.h>
#include <stdio.h> main()
A char * text = "sir de separat in bucati"; char * separator = " "; char * cuvint;

cuvint = strtok(text, separator);
while (cuvint != NULL) A printf("%s\n", cuvint); cuvint = strtok(NULL, separator);
S
S
-------------------------------------------------------

Daca executati acest program veti obtine:

------------------------------------------------------ sir de separat in bucati
-------------------------------------------------------

Prima oara cind apelez strtok(text, separator), aceasta testeaza daca "text" nu e 0 (NULL), deci il memoreaza undeva intr-un buffer intern functiei. Dupa aceasta cauta prima aparitie a unui caracter din "separator", pe care o inlocuieste cu un caracter 0 (sau \0, sfirsit de sir). La intrare vom avea:

------------------------------------------------------ text = |s|i|r| | |d|e| |s|e|p|a|r|a|t| | | |i|n| |b|u|c|a|t|i|\0|
----------------------------------------------------------

si la iesire:

------------------------------------------------------ text = |s|i|r|\0| |d|e| |s|e|p|a|r|a|t| | | |i|n| |b|u|c|a|t|i|\0|
---------------------------------------------------------- ^ ^ cuvint am ramas aici

-------------------------------------------------------

Cu alte cuvinte sirul "text" a fost modificat, rezultatul "cuvint" puncteaza la primul cuvint, care a fost separat cu un 0 de restul sirului, iar strtok() tine minte unde a ramas. A doua oara cind apelez strtok() va avea un argument 0 in locul lui "text". Asta inseamna: continua de unde s-a ramas. Asa ca rezultatul va fi:

------------------------------------------------------ text = |s|i|r|\0| |d|e|\0|s|e|p|a|r|a|t| | | |i|n| |b|u|c|a|t|i|\0|
----------------------------------------------------------- ^ ^ cuvint am ramas aici
-------------------------------------------------------

Data viitoare se va obtine:

------------------------------------------------------ text = |s|i|r|\0| |d|e|\0|s|e|p|a|r|a|t|\0| | |i|n| |b|u|c|a|t|i|\0|
------------------------------------------------------------ ^ ^ cuvint am ramas aici
-------------------------------------------------------

Dupa inca doua apeluri se va obtine rezultat 0, pentru ca s-a ajuns la sfirsitul sirului:

------------------------------------------------------ text = |s|i|r|\0| |d|e|\0|s|e|p|a|r|a|t|\0| | |i|n|\0|b|u|c|a|t|i|\0|
------------------------------------------------------------- ^ cuvint=0 am ramas aici
-------------------------------------------------------

Iata cum strtok() desparte un sir de caractere. strtok() este o functie care poate fi implementata fara ajutorul vreunui apel de sistem, pentru ca manipuleaza simple array-uri de caractere.

2.5 Apeluri de sistem

Ultimele 3 functii sunt apeluri de sistem tipice Unix, care au de-a face cu crearea de noi procese.

2.6.6 fork()

fork() este singura metoda prin care in Unix se poate crea un nou proces (vezi lab socn6.txt). Cind un proces executa fork(), el da nastere unui alt proces absolut identic cu el insusi, care se numeste fiul lui, si care isi continua executia in paralel cu tatal. Amindoua procesele isi continua executia ca si cum tocmai ar fi executat instructiunea fork(); singura diferenta dintre ele este ca tatal va primi ca rezultat al executarii lui fork() un numar nenul, care identifica fiul, iar fiul va primi un 0.

Figura explica si numele: "fork" inseamna "furculita".

------------------------------------------------------ ------------- | | proces=12 inainte | r = fork() | de | | fork() -------------- ___________
| \ v v
-------------- ------------- | | proces=12 | | proces=13 dupa | r = fork() | (tata) | r = fork() | (fiu) fork() | (r=13) | | (r=0) |
-------------- ------------- -------------------------------------------------------

In figura de mai sus, parintele (cu numarul de proces 12) creaza un copil, care intimplator capata numarul 13. Dupa instructiunea fork() avem 2 procese,
12 si 13, care se executa in paralel. Cel cu numarul 12 (parintele), va avea r=13, numarul copilului, iar copilul, desi va executa acelasi cod, din acelasi punct, va avea r=0.

2.7.7 wait()

Cu apelul de sistem wait() un proces parinte asteapta terminarea unui copil.
Parintele este blocat din executie pina unul dintre copii lui se termina, dupa care wait() returneaza parintelui niste informatii despre cauza terminarii.
(Argumentul lui wait() este un pointer spre un int unde se vor pune aceste informatii; in programul nostru pointerul este 0; rezultatul lui wait() este pid copil)

2.8.8 execvp()

Rezultatul compilarii unui program este un fisier executabil (de exemplu, mai sus cind ati compilat shell.c ati obtinut shell). Apelul de sistem exec() determina nucleul sa citeasca un fisier executabil in memorie, sa-l transforme in imaginea unui proces si sa-l execute, furnizind si argumentele care vor fi trecute noului proces. Procesul care executa apelul acesta de sistem este complet inlocuit cu imaginea noului fisier. Exista mai multe variante ale apelului de sistem exec() (vezi socn3.txt). execvp() este exec cu un vector de pointeri spre argumentele procesului. Declaratia din <unistd.h> este:

------------------------------------------------------ int execvp(const char *fisier, char * const argumenteai);

-------------------------------------------------------

Primul parametru este numele fisierului executabil. Al doilea parametru este un array in care fiecare obiect este un pointer la un argument pasat procesului. Argumentele sunt simple siruri de caractere. Argumentele sunt primite de functia main() a procesului exec-utat in parametrul argv:

------------------------------------------------------ int main(int argc, char * argvai)
^^^^^^ argumentele transmise de exec
-------------------------------------------------------

2.9 Programul shell.c

Iata inca odata programul de mai sus, cu headerele incluse, indentat si comentat:

------------------------------------------------------ #include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int a, /* char oarecare din sirul citit */ ba99i, /* comanda tastata; folosit ca un char ai */
*c, /* pointer spre argumentul curent */ da99i; /* pointeri spre lista de argumente */

int main()
A
while(printf(">"), /* prompt */ c=d, /* argumentele vor fi plasate in vectorul d */
*c=a=gets(b)) A /* citeste prima linie; a = b */ for( ;
*++c=strtok(a," ") ; /* separa urmatorul cuvint; pune-l in d */ a=0); /* a = NULL -> folosim acelasi buffer */ fork() ? /* eu sunt tatal? */
wait(0) : /* da, asteapta copilul! */ execvp(*d,d+1); /* nu: executa comanda data cu argumente */
SS
-------------------------------------------------------

In primul rind programul foloseste numere intregi pentru a memora atit caractere cit si pointeri. Variabila a puncteaza la sirul citit de la utilizator, pentru a-l imparti in felii cu strtok(). Variabila b contine chiar comanda tastata (e folosita ca un array de caractere). Variabila d va contine la sfirsitul executarii lui strtok() pointerii catre argumente dati lui execvp().
In fine, variabila c parcurge casutele lui d, aratind care vine la rind.

Situatia la inceput arata astfel:

-------------------------------------------------------

| | | | | | | | | | | | | ....| b | | | | | | | | | | | | | ....| d
-------------------------------- --------------------------------
^ ^ a c
------------------------------------------------------
Sa presupunem ca utilizatorul tasteaza la prompt textul echo a1 a2.
Atunci dupa executarea for-ului situatia va fi urmatoarea:

-------------------------------------------------------

|e|c|h|o|\0|a|1|\0|a|2|\0| | | | ....| b
-------------------------------------- ^ ^ ^
| ________| |
| | _____________/
| | |
|*|*|*|0| | | | | | | | | | | ....| d
----------------------------------- ^ c
-------------------------------------------------------

Din cauza asta, dupa ce copilul e facut si parintele este dat in background, copilul executa comanda indicata de primul parametru al lui execvp(), *d,
(care puncteaza spre sirul echo), iar argumentele lui echo sunt cuprinse in vectorul d, incepind de la casuta 1 (d+1).

3 Un alt exemplu

Prezentam un nou program shell, de data asta mai sofisticat. Acesta poate recunoaste mai multe comenzi pe aceeasi linie, pipe-uri (comanda1 | comanda2), redirectari in fisiere (comanda >fisier1 <fisier2), comanda interna cd.

------------------------------------------------------ #define D ,close(

char *c,q a512 i,ma 256
i,*va 99i, **u, *ia3i;int fa2i,p;main ()Afor
(mam a60i= ma62 i=32 i=ma* m=124 ami= 9i=6; e(-8) ,gets (1+( c=q) )|| exit (0); r(0,0)
)for( ;*++ c;); Sr(t, o)A *i=i a2i= 0;for
(u=v +98 ;ma*--ci ^9;m a*ci &32 ?ia*c
&2i= *u,u- v^98 &&++u:

3 )if(!ma*ci)Afor(*++c=0;!ma*--ci;);
* --u= ++c;Su-v^98?strcmp(*u,"cd")?*c?pipe(f),o=fa
1 i:
4 ,(p=fork())?e(p),o?r(o,0)D o)D*f):
1 ,wait(0):(o?dup2(*f,0)D*f)D o):*i?
5 D 0),e(open(*i,0)):
9 ,t?dup2(t,1)D t):ia
2 i?
6 D 1),e(creat(ia2i,438)):
5 ,e(execvp(*u,u))):e(chdir(ua1i)*2):
3 ;Se(x)Ax<0?write(2,"?\n$ "-x/4,2),x+1||exit(1):
5 ;S

-------------------------------------------------------

4 Concluzii

Pentru nucleu, shell-ul este un proces ca toate celelalte, care se executa fara nici un fel de privilegii si care ocazional face cite un apel de sistem.
Shell-urile citesc comenzi de la utilizator, pe care apoi le interpreteaza si le transforma intr-o serie de apeluri de sistem, care in general culmineaza cu executarea unuia sau mai multor fisiere.

Tema :
-imaginati alte shelluri


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