2. cvičenie – shell ?

Jednoduchý xv6 shell

V tomto cvičení sa naučíte, ako UNIXovské shelly používajú základné systémové volania.

Vašou úlohou je napísať jednoduchý shell pre xv6. Mal by byť schopný spustiť príkaz s argumentami, zvládať presmerovať vstup/výstup a podporovať aspoň jednu rúru v príkaze. Po jeho dokončení by ste v ňom mali bez problémov spustiť nasledovné príkazy (mal by mať podobné správanie ako shell xv6 sh):

Zdrojové súbory shellu umiestnite do user/nsh.c a príslušne modifikujte Makefile, aby ho bolo možné skompilovať. Pri písaní a testovaní shellu modifikujte len user/nsh.c. Váš shell musí byť od iných zdrojových súborov nezávislý. Váš shell by mal používať @ (zavináč) ako znak vstupu príkazu, aby ste si ho nepomýlili so skutočným shellom. Práca v xv6 s vaším shelom môže vyzerať nasledovne:

Na tomto cvičení nesmiete používať dynamickú alokáciu pamäte pomocou malloc(). Namiesto nej používajte lokálne (na zásobníku) a globálne premenné. Je v poriadku, ak stanovíte limity na maximálnu dĺžku príkazu, maximálny počet argumentov, maximálnu dĺžku jedného argumentu a podobne.

Pripravili sme pre vás (teda nie my, ale ujovia z MIT) testovací program testsh. Jeho zdroják nájdete v user/testsh.c. Keď si budete myslieť, že máte shell hotový, môžete si otestovať práve pomocou tohto programu. Cvičenie ste nedokončili, až kým ste neprešli všetkými testami. Ukážka:

Prepnutie vetvy

V tomto a ďalších cvičeniach budeme postupne rozširovať xv6, ale aby sme v zdrojákoch mali poriadok, pre každé cvičenie vytvoríme samostatnú vetvu. Ak ste pracovali na utilitách v predchádzajúcom cvičení, teraz je vhodný čas uložiť si prácu do repozitára. Použite na to príkazy:

Teraz sa môžete prepnúť do vetvy sh:

Nie je potrebné, aby ste do tejto vetvy mergovali riešenie predchádzajúceho cvičenia (utility). Ak by ste odtiaľ potrebovali nejaký kód, môžete to urobiť, ale ináč sú skoro všetky cvičenia navzájom nezávislé.

Pomocou príkazu git checkout nazov-vetvy môžete prepínať medzi jednotlivými vetvami. Pred prepnutím ale musíte commitnúť vaše zmeny. Ak tak neurobíte, tak git vám aj tak vynadá (ako ináč, keď ho napísal Linus Torvalds).

Pomôcky

Neimplementujte funkcie, ktoré nie sú kontrolované v testoch. Váš shell nemusí podporovať zátvorky a úvodzovky (ich implementáciu vám ale nezakazujeme).

Knižka o céčku od Kernighana a Ritchieho je plná užitočných kúskov kódu – môžete ich voľne používať. Možno sa vám bude hodiť funkcia gettoken() z parsera v sekcii 5.12.

Nsh je oveľa jednoduchší ako pôvodný shell xv6, takže pre vaše programátorské pohodlie bude najlepšie, ak ho začnete písať od začiatku. Nič vám ale nebráni nakuknúť do zdrojákov xv6 shellu (user/sh.c) pre inšpiráciu.

V xv6 je pripravená malá knižnica funkcií jazyka C v user/ulib.c. Môžete ju používať, okrem funkcie malloc(), ako sme už spomenuli vyššie.

Nezabudnite zatvoriť nepotrebné súborové deskriptory. Je to potrebné z dvoch dôvodov:

  • xv6 má obmedzený počet súborových deskriptorov, s ktorými môže pracovať
  • proces čítajúci z rúry neuvidí koniec súboru, až kým nie sú všetky zapisovacie deskriptory danej rúry uzavreté

Nezabudnite na kontrolu návratových hodnôt systémových volaní!

testsh presmeruje štandardný výstup vášho shellu. To znamená, že na obrazovke neuvidíte jeho výstup. Chybové a ladiace hlášky vypisujte na štandardný chybový výstup (súborový deskriptor 2) prostredníctvom funkcie fprintf(2,...).

Ak sa testsh sťažuje na váš shell, dovoľujeme vám modifikovať testsh tak, aby vypísal príkaz, ktorý sa snaží spustiť vo vašom shelli. Váš shell môžete tiež upraviť, aby vypísal argumenty, ktoré dostane od testovacieho skriptu na spustenie. To vám môže uľahčiť hľadanie chýb.

Ďalej vám dovoľujeme upraviť funkciu one() v testsh.c tak, aby vypísala výstup z vášho shellu a výstup, ktorý očakávala. Po porovnaní môžete zistiť príčinu chyby.