Tema 3 - Mini-shell

Scopul acestei teme este realizarea unui shell simplu, compatibil cu sh;

Informații generale

Deadline: 5 Aprilie, ora 23:55
Punctaj: 2 puncte din nota
Incarcarea temei: vmchecker.cs.pub.ro
Incarcarea cu intarziere: 0.1 punct / zi (maxim 4 zile)

Cunoștințe evaluate

  • Folosirea functiilor POSIX pentru lucrul cu fisiere (os.open, os.read, os.write, …)
  • Folosirea functiilor pentru lucrul cu procese (os.fork, os.exec si os.waitpid, …)
  • Intelegerea principiilor de lucuru cu fisier si procese

Reguli

  1. Tema trebuie sa contina un fisier Readme in care sa explicati cum ati facut tema (-0.1p)
  2. Aveti voie sa folositi doar functii POSIX (biblioteca os)
  3. Aveti voie sa folositi doar limbajul Python (Python 3)
  4. O temă care trece toate testele automate va obține 10 puncte din 10 (daca nu trișează folosind API interzis, cum ar fi funcția f.write(), os.popen, caz în care nu va fi punctată).

Copierea

Tema se rezolva individual. Orice tentativa de copiere va rezulta in 0p pentru tema respectiva. Vom utiliza si sisteme automate de detectare a copierii. Daca avem dubii, va vom adresa intrebari suplimentare legate de tema.

Intrebari

Daca aveti intrebari legate de tema, va rugam sa scrieti un issue pe repository-ul de github repository cu titlul de forma [mini-shell] <titlul intrebarii voastre>. Aveti nevoie de un cont de github pentru a scrie intrebari.

NU PUBLICATI COD SURSA. Acesta va fi considerata copiere si se va penaliza cu 0p pe tema pentru voi.

Daca doriti sa primiti un email cand se pun intrebari noi sau cand apar raspunsuri, accesati github repository si faceti click pe Watch.

Mini Shell

Să se implementeze un shell simplu, care suportă execuția de comenzi externe cu argumente multiple, comenzi interne, redirectări, pipe-uri. Shell-ul trebuie să suporte execuția de comenzi compuse, cu oricâți operatori.

Comnezi interne: comenzi pe care shell-ul le execute: cd, pwd, exit … Comenzi externe: comenzi care sunt de fapt executabile separate: ls, vim, tree, nano, …

Regula este asa: se verifica daca este comanda interna, daca nu, se presupune ca este o comanda externa.

Shell-ul trebuie să suporte următorii operatori de execuție:

  • operatorul de secvențiere ;
    • va fi folosit pentru a executa comenzile “pe rând”;
    • de exemplu, expr1; expr2 va avea ca efect mai întâi execuția comenzilor expr1 și, după terminarea execuției acestora, execuția comenzilor expr2;
  • operatorul de paralelism &
    • va fi folosit pentru a executa comenzile în paralel;
    • de exemplu, expr1 & expr2 va avea ca efect execuția comenzilor expr1 și a comenzilor expr2 în paralel;
    • în implementare NU aveți voie să vă reapelați singuri executabilul.
      execv("./my_homework", "command");
  • operatorii de execuție condiționată && și ||
    • vor fi folosiți pentru a executa comenzile în funcție de codul de eroare;
    • expr1 && expr2 va avea ca efect execuția comenzilor expr2 doar în cazul în care comenzile expr1 au ca rezultat un cod de eroare 0;
    • expr1 || expr2 va avea ca efect execuția comenzilor expr2 doar în cazul în care comenzile expr1 au ca rezultat un cod de eroare diferit de zero.
  • operatorul pipe | este interpus intre doua comenzi. Efectul este redirectionarea a ceea ce scrie pe ecran primul proces

spre ceea ce citeste de la tastatura al doilea proces. De exemplu, expr1 | expr2 va avea ca efect execuția comezilor expr1 cu stdout-ul redirectat în stdin-ul comenzilor expr2;

Prioritatea operatorilor de execuție este, de la cel mai prioritar la cel mai puțin prioritar:

  1. operatorul pipe
  2. operatorii de execuție condiționată
  3. operatorul de paralelism
  4. operatorul de secvențiere

Shell-ul trebuie, de asemenea, să suporte și următorii operatori de redirectare:

  • < nume_fisier pentru redirectarea intrării standard din fișierul nume_fisier;
  • > nume_fiser pentru redirectarea ieșirii standard în fișierul nume_fisier;
  • 2> nume_fisier pentru redirectarea ieșirii de eroare standard în fișierul nume_fisier;
  • &> nume_fisier pentru redirectarea ieșirii standard și ieșirii de eroare standard în fișierul nume_fisier;
  • >> nume_fisier pentru redirectarea ieșirii standard în fișierul nume_fisier în modul append;
  • 2>> nume_fisier pentru redirectarea ieșirii de eroare standard în fișierul nume_fisier în modul append.

În fine, shell-ul trebuie să suporte următoarele comenzi interne:

  • exit și quit pentru terminarea shell-ului
  • cd director pentru schimbarea directorului curent
    • ATENȚIE: Mini-shell-ul trebuie să funcționeze în continuare la introducerea comenzii cd fără parametru. Nu se impune implementarea comportamentului din bash (schimbarea directorului curent cu directorul home al utilizatorului curent) și nici o valoare de exit pentru acest scenariu (practic, cd fără parametru poate să nu facă nimic, dar să nu rămână cu comportament nedefinit care să ducă la erori).

Shell-ul trebuie să suporte subcomenzi:

  • formatul de utilizare este comanda $(comanda sau lista comenzi)
  • pentru acestea, se va executa tot ce se gaseste in paranteze si rezultatul se va inlocui in lista de comenzi

Precizări generale

  • Pentru a simplifica implementarea temei, puteți folosi parserul implementat de noi. Pentru detalii despre parser, citiți fișierul README din arhivă. Exemplu de utilizare a parserului găsiți în sursa cmd.py, care poate fi folosită ca schelet pentru temă.
  • Promptul afișat de shell este impus pentru a facilita testarea automată și este \$ (adică se va afișa caracterul $ urmat de un spațiu).
  • Numele fișierului principal din temă trebuie să fie cmd.py.

Sugestii de rezolvare

Tema este relativ complexa fata de cea anterioara. Un sablon pentru inceperea temei este disponibil in repository in directorul tema3.

Recomandăm rezolvarea și testarea din aproape în aproape a temei, după pași:

  1. rularea de comenzi simple (ls, ls -l)
  2. rularea de comenzi interne (cd, exit, quit)
  3. implementarea redirectărilor (operatorii <, >, 2>, &>, >>, 2>>)
  4. secvențierea comenzilor (operatorii &&, ||, ;)
  5. implementarea operatorilor & (paralel)
  6. |
  • Aveți mai jos câteva exemple de comenzi și rezultatul generat de acestea:
 $ ls
 Makefile	  README.checker  mini-shell	mini-shell.o  parser
 Makefile.checker  inputs	  mini-shell.c	outputs       tags
 
 $ cat /etc/services | grep telnet
 telnet		23/tcp
 rtelnet	107/tcp				# Remote Telnet
 rtelnet	107/udp
 telnets	992/tcp				# Telnet over SSL
 telnets	992/udp
 tfido		60177/tcp			# fidonet EMSI over telnet
 
 $ uname -a ; ps 
 Linux bogdan-desktop 2.6.31-19-generic #56-Ubuntu SMP Thu Jan 28 02:39:34 UTC 2010 x86_64 GNU/Linux
   PID TTY          TIME CMD
  6078 pts/0    00:00:00 bash
  6190 pts/0    00:00:00 mini-shell
  6200 pts/0    00:00:00 ps
 
 $ date && sleep 1 ; echo date
 Mon Feb  8 13:40:25 EET 2010
 date
 
 $ date && sleep 1; date
 Mon Feb  8 13:40:49 EET 2010
 Mon Feb  8 13:40:50 EET 2010
 
 $ true && date
 Mon Feb  8 13:41:16 EET 2010
 
 $ false && cat mini-shell.c
 
 $ false || date
 Mon Feb  8 13:42:36 EET 2010
 
 $ cat /et/services
 cat: /et/services: No such file or directory
 
 $ gcc > tmp; echo sep; cat tmp
 gcc: no input files
 sep
 
 $ strace -e trace=read ls 2> strace.out   
 Makefile	  README.checker  mini-shell	mini-shell.o  parser	  tags
 Makefile.checker  inputs	  mini-shell.c	outputs       strace.out  tmp
 
 $ head -1 strace.out
 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@#\0\0\0\0\0\0@"..., 832) = 832
 
 $ pwd; cd Teme; pwd
 /home/bogdan/Documents/SO/Solutii
 /home/bogdan/Documents/SO/Solutii/Teme
 
 
 > exit

Materiale ajutătoare

Parcurgerea linii de comanda

Pentru parcurgerea linii de comanda, am scris noi deja un parser (parser.py) pe care il puteti folosi. Incepeti tema in fisierul cmd.py aflat in sablon.

Pentru a vizualiza cum arata structura de date primita de la parser, rulati scriptul din cmd.py după care introduceți o comandă de la tastatură.

Pentru a putea rula fișierul cmd.py, trebuie să instalați biblioteca bashlex (pip3 install bashlex --target=.).

$ pip3 install bashlex --target=.
$ python3 cmd.py
 
$ ls
ls
{'op': 4, 'com1': None, 'com2': None, 'commands': [<parse.SimpleCommand object at 0x100b4bfd0>], 'input': None, 'output': None, 'err': None, 'append_err': False, 'append_out': False}
commands
ls

Structura intoarsa in cmd.py

Prin apelarea parse.parse(line), se va intoarce un obiect de tipul Command.

Clasa Command

Proprietati:

  • op - tipul de operatie al comenzii (vezi tipurile existente mai jos)
  • com1 - contine un obiect de tip Command, prima comanda din lista, daca op este OP_NONE, com1 va fi egal cu None
  • com2 - contine un obiect de tip Command, a doua comanda din lista, daca op este OP_NONE, com2 va fi egal cu None
  • commands - contine lista de comenzi si argumente (doar daca op este OP_NONE), daca unul din argumente este de forma $(cmd_list), elementul va fi de tipul Command, in caz contrar, elementul va fi de tipul SimpleCommand

Pentru a verifica tipul unui obiect, folositi structura isinstance (obj, class).

  • input - contine fisierul de input, daca intrarea este redirectata (<)
  • output - contine fisierul de output, daca iesirea standard este redirectata (>, »)
  • err - contine fisierul de error_output, daca iesirea de eroare este redirectata (2>, , &>, )
  • append_err - are valoarea True daca iesirea de eroare face append (, )
  • append_out - are valoarea True daca iesirea face append (», )

Clasa SimpleCommand

Obiectul de tip SimpleCommand este folosit in cadrul comenzilor cu op egal OP_NONE (comanda simpla). Acestea se gasesc in lista commands si sunt fie comenzi, fie parametrii unor comenzi.

Proprietati:

  • word - textul efectiv al comenzii sau al parametrului

Tipurile de operatii

Modulul parse expune urmatoarele tipuri de operatii (valoarea lui command.op):

  • OP_CONDITIONAL_NZERO - operatia este de tipul ( cmd1 && cmd2)
  • OP_CONDITIONAL_ZERO - operatia este de tipul (cmd1 || cmd2)
  • OP_SEQUENTIAL - operatia este de tipul (cmd1 ; cmd2)
  • OP_PARALLEL - operatia este de tipul (cmd1 & cmd2)
  • OP_NONE - operatia este de tipul (comanda parametrii)
  • OP_PIPE - operatia este de tipul (cmd1 | cmd2)

Testarea locala a temei

Pentru a testa tema local, va recomandam ca prima data sa rulati comanda make -f Makefile.checker in directorul devoir3. Astfel se vor instala toate modulele necesare pentru rularea fisierului cmd.py. In continuare, puteti rula tema folosind python3 cmd.py, iar in directorul verify veti gasi toate comenzile pe care tema trebuie sa le ruleze.

FAQ

  • Q: Tema 3 se poate face în Python 2?
    • A: Nu.
  • Q: Trebuie optimizat numărul de fork-uri? Spre exemplu, în cazul comenzii a|b|c trebuie sa am 3 forkuri sau pot să am 4 sau 5?
    • A: Nu este obligatoriu să optimizați numărul de fork-uri. Totuși, în general este bine să aveți în vedere eficientizarea consumului de resurse.
  • Q: Shell-ul trebuie să se comporte ca un shell adevărat (sh, bash) în situația … ?
    • A: Funcționalitatea minimă necesară este cea din enunțul temei. Daca implementați ceva în plus, precizați în README. Exemple de funcționalitate care nu este cerută: updatarea unor variabile de mediu (gen $OLDPWD și $PWD), history, multe altele … (vezi man bash pentru o idee despre funcționalitatea unui shell complet :-) )
  • Q: Am voie să nu folosesc parserul din enunț dacă doresc să scriu eu altul echivalent?
    • A: Da.
  • Q: Avem voie sa folosim:
    args = ["/bin/bash", "-c", command]
    os.execv(args[0], args);
    • A: Nu.
  • Q: Am voie să fac os.execv pe tema mea pentru a executa o parte din arbore independent?
    • A: Nu.

Trimiterea temei

Tema se va incarca pe vmchecker. Logati-va pe site cu folosind utilizatorul de pe moodle, selectati cursul Systemes d'Explotation (FILS) si incarcati arhiva temei.

Readme

Fisierul readme are urmatorul format:

Numele vostru intreg
Grupa

Descrierea rezolvarii temei, de ce ati ales anumite solutii, etc.

Arhiva temei

Pentru a incarca tema, urmariti pasii:

  1. Creati o arhiva zip (nu rar, ace, 7zip sau alt format) care sa contina:
    • toate fisierele Python (*.py)
    • fisierul principal cu numele cmd.py
    • fisierul Readme
  2. logati-va pe vmchecker
  3. selectati cursul Systemes d'Explotation(FILS)
  4. selectati 3. Mini-Shell
  5. incarcati arhiva

Arhiva trebuie sa contina toate fisierele (principale) in radacina, nu in subdirectoare. NU arhivati directorul temei, arhivati DIRECT fisierele.

NU includeti directoarele specifice bibliotecii bashlex (pycache, bashlex, bashlex-0.14.dist-info).

Dupa ce incarcati arhiva, vmchecker va rula:

unzip archive.zip homework
cd homework
make -f Makefile.checker
sde/teme/tema_ro_3_python.txt · Last modified: 2020/04/02 17:00 by ioana_maria.culic
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0