Teme:Mini-shell

Termen de predare: Marți 31 Martie 2009, ora 23.59 (2009-03-31)

Enunț
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.

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, executia comenzilor expr2;
 * operatorul de paralelism "&amp;"
 * va fi folosit pentru a executa comenzile in paralel;
 * de exemplu, expr1 &amp; expr2 va avea ca efect execuția comenzilor expr1 și a comenzilor expr2 în paralel;
 * operatorul "|</tt>" (pipe)
 * va fi folosit pentru înlănțuirea comenzilor;
 * de exemplu, expr1 | expr2</tt> va avea ca efect execuția comezilor expr1</tt> cu stdout-ul redirectat în stdin-ul comenzilor expr2</tt>;
 * operatorii de execuție condiționată "&amp;&amp;</tt>" și "||</tt>"
 * vor fi folosiți pentru a executa comenzile în funcție de codul de eroare;
 * expr1 &amp;&amp; expr2</tt> va avea ca efect execuția comenzilor expr2</tt> doar în cazul în care comenzile expr1</tt> au ca rezultat un cod de eroare 0</tt>;
 * expr1 || expr2</tt> va avea ca efect execuția comenzilor expr2</tt> doar în cazul în care comenzile expr1</tt> au ca rezultat un cod de eroare diferit de zero.

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


 * 1) operatorul |
 * 2) operatorii de execuție conditionată
 * 3) operatorul de paralelism
 * 4) operatorul de secvențiere

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


 * "&lt; nume_fisier</tt>" pentru redirectarea intrării din fișierul nume_fisier</tt>;
 * "&gt; nume_fiser</tt>" pentru redirectarea ieșirii standard în fișierul <tt>nume_fisier</tt>;
 * "<tt>2&gt; fisier</tt>" pentru redirectarea ieșirii de eroare standard în fișierul <tt>nume_fisier</tt>;
 * "<tt>&amp;&gt; fisier</tt>" pentru redirectarea ieșirii standard și ieșirii de eroare standard în fișierul <tt>nume_fisier</tt>;
 * "<tt>&gt;&gt;</tt>" pentru redirectarea ieșirii standard în fișierul <tt>nume_fisier</tt> în modul "append";
 * "<tt>2&gt;&gt;</tt>" pentru redirectarea ieșirii de eroare standard în fișierul <tt>nume_fisier</tt> în modul "append".

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


 * <tt>exit</tt> si <tt>quit</tt> pentru terminarea shell-ului;
 * <tt>cd director</tt> pentru schimbarea directorului curent.

Shell-ul trebuie să suporte variabile de mediu:
 * formatul de utilizare este <tt>$VARIABILA_DE_MEDIU</tt> identic pe Linux și pe Windows;
 * variabilele de mediu sunt moștenite de la shell-ul părinte (Bash) sau sunt definite în mini-shell;
 * definirea variabilelor se face sub forma <tt>NUME_VARIABILA=valoare</tt>;
 * nu trebuie tratat cazul în care <tt>valoare</tt> conține referiri la alte variabile de mediu.

Precizări generale

 * Pentru a simplifica implementarea temei, puteți folosi [[media:parser_mini-shell.zip|parserul implementat de noi]]. Pentru detalii despre parser, citiți fișierul <tt>README</tt>.
 * Promptul afișat de shell este impus pentru a facilita testarea automata și este "&gt; " (adică se va afișa caracterul <tt>&gt;</tt> urmat de un spațiu).
 * Numele executabilului temei trebuie să fie <tt>mini-shell</tt> pe Linux, respectiv <tt>mini-shell.exe</tt> pe Windows.
 * Din cauza diferenței între Windows și Linux la crearea de noi procese (<tt>CreateProcess</tt> vs. <tt>fork</tt> + <tt>exec</tt>) s-ar putea să nu puteți folosi același tip de parcurgere a arborelui sintactic și pe Windows și pe Linux. Daca vreți să reutilizați concepte/cod de pe Linux pe Windows, concepeți parcurgerea să funcționeze și cu funcția <tt>CreateProcess</tt> de pe Windows.
 * În rezolvarea temei puteți porni de la exemplul de utilizare a parserului (<tt>UseParser.cpp</tt> sau <tt>CUseParser.c</tt>).
 * Recomandăm rezolvarea și testarea din aproape în aproape a temei:
 * rularea de comenzi simple
 * rularea de comenzi interne (<tt>cd</tt>, <tt>exit</tt>, <tt>quit</tt>)
 * implementarea redirectărilor (operatorii <tt>&gt;</tt>, <tt>&lt;</tt>, <tt>2&gt;</tt>, <tt>&amp;&gt;</tt>, <tt>&gt;&gt;</tt>, <tt>2&gt;&gt;</tt>)
 * variabile de mediu
 * secvențierea comenzilor (operatorii <tt>&amp;&amp;</tt>, <tt>||</tt>, <tt>;</tt>)
 * implementarea operatorilor <tt>&amp;</tt> (paralel) și <tt>|</tt> (pipe)
 * Mai jos sunt prezentate câteva exemple de comenzi și rezultatul generat de acestea:

Precizări Windows

 * Tema se va rezolva folosind doar funcții Win32. Se pot folosi, de asemenea, și funcțiile de formatare <tt>printf</tt>, <tt>scanf</tt>, funcțiile de alocare de memorie <tt>malloc</tt>, <tt>free</tt> și funcțiile de lucru cu șiruri de caractere (<tt>strcat</tt>, <tt>strdup</tt>, etc.)
 * Pentru partea de I/O și procese se vor folosi doar functți Win32. De exemplu, funcțiile <tt>open</tt>, <tt>read</tt>, <tt>write</tt>, <tt>close</tt> nu trebuie folosite, în locul acestor trebuind să folosiți <tt>CreateFile</tt>, <tt>ReadFile</tt>, <tt>WriteFile</tt>, <tt>CloseHandle</tt>.
 * Pentru a permite transmiterea de caractere speciale în argumente (spre exemplu <tt>echo "int main { return 0; }"</tt>) recomandăm să "îngrădiți" argumentele liniei de comandă a <tt>CreateProcess</tt> cu ghilimele.

Precizări Linux

 * Tema se va rezolva folosind doar funcții POSIX. Se pot folosi de asemenea și funcțiile de formatare <tt>printf</tt>, <tt>scanf</tt>, funcțiile de alocare de memorie <tt>malloc</tt>, <tt>free</tt> și funcțiile de de lucru cu șiruri de caractere (<tt>strcat</tt>, <tt>strdup</tt>, etc.)
 * Pentru partea de I/O și procese se vor folosi doar funcții POSIX. De exemplu, funcțiile <tt>fopen</tt>, <tt>fread</tt>, <tt>fwrite</tt>, <tt>fclose</tt> nu trebuie folosite, în locul acestor trebuind să folosiți <tt>open</tt>, <tt>read</tt>, <tt>write</tt>, <tt>close</tt>.

Testare

 * Pentru simplificarea procesului de corectare a temelor, dar și pentru a reduce greșelile temelor trimise, corectarea se va realiza automat cu ajutorul unor test publice ([[media:test_mini-shell_lin.zip|linux]], [[media:test_mini-shell_win.zip|windows]]).
 * Există 15 teste. Fiecare test valoarează 0.6 puncte. Se pot obține maxim 9 puncte prin trecerea testelor. Se acordă 1 punct din oficiu.
 * Pentru a trece testul 15, este obligatoriu să respectați formatul mesajului de eroare impus. Mesajul de eroare trebuie scris la <tt>stderr</tt> și trebuie să fie identic cu cel așteptat de teste (vezi <tt>test_15_ref.txt</tt> din teste).
 * O temă care trece cele 15 teste automate va obține 10 puncte din 10 (daca nu trișează folosind API interzis, cum ar fi funcția <tt>system</tt>, caz în care nu va fi punctată).
 * Din punctajul temei se vor scădea automat puncte pentru întârzieri și pentru warning-uri. La revizia temei, se poate scădea suplimentar pentru nerespectărea criteriilor scrise la secțiunea reguli. Astfel:
 * <tt>-0.1</tt> pentru fișier Makefile incorect (de exemplu compilează de fiecare dată totul)
 * <tt>-0.2</tt> pentru fișier README necorespunzator
 * <tt>-0.2</tt> surse necorespunzător comentate
 * <tt>-0.3</tt> neverificarea condițiilor de eroare sau/și neeliberarea de resurse
 * <tt>-0.2</tt> diverse alte probleme constatate în implementare
 * În cazuri excepționale se poate scădea mai mult decât este menționat mai sus.

Notă
cl /nologo /W3 /EHsc /Za /c parser.yy.c parser.yy.c parser.yy.c(1302) : warning C4018: '<' : signed/unsigned mismatch
 * La corectarea temei nu se va ține cont de warning-urile cauzate de parser. De exemplu:

FAQ

 * Q: Cum pot să citesc arhivele listei de discuții?
 * A: O variantă este cu Opera: File -&gt; Import and export -&gt; Import mail -&gt; Import generic mbox file -&gt; alegeți fișierele respective.


 * Q: Temele se pot face în C++?


 * A: Da.


 * Q: Am voie sa folosesc funcții POSIX pe Windows?
 * A: La toate temele de SO pe Windows se va folosi Win32 API, nu POSIX. Oricum, <tt>fork</tt> și <tt>exec</tt> nu sunt suportate pe Windows XP decât după instalarea "Unix Services for Windows".


 * Q: La temele de Windows trebuie să folosesc funcțiile de API în versiunea Unicode, ANSI, sau generică?
 * A: Nu este impus să folosiți o versiune anume. Aveți, totuși, grijă să folosiți corect funcțiile (acestea primesc parametri de tip CHAR pentru versiunea ANSI, WCHAR pentru Unicode și TCHAR în versiunea generică). Pentru detalii consultați Unicode in the Windows API.


 * Q: Ce fac dacă am intâlnit un caz limită al carui comportament nu este precizat în enunț?
 * A: În general la temele de SO, pentru cazuri limită ce nu apar în testele publice sau în enunt, se acceptă orice comportament documentat în README. Un exemplu este comportamentul pentru "command | cd /something". Daca nu sunteți siguri, întrebați pe lista de discuții.


 * Q: Trebuie optimizat numărul de fork-uri? Spre exemplu, în cazul comenzii <tt>a|b|c</tt> 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 <tt>$OLDPWD</tt> și <tt>$PWD</tt>), 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.

Lista de discuții
Dacă aveți întrebări sau nelămuriri legate teme, laboratoare sau curs, puteți căuta, consulta sau [mailto:so@cursuri.cs.pub.ro trimite un mail pe] lista de discuții (trebuie să fiți înregistrați).