Project: Mini Shell
Proiectul final. Vom construi o bucată dintr-un shell, programul care rulează când deschizi un terminal. Acesta combină fork, wait și tot ce am învățat despre procese
Un shell real face așa: citește o comandă, face fork, copilul execută comanda, părintele așteaptă. Vom construi o versiune simplificată care citește comenzi dintr-o coadă de teletype și le rulează una câte una, demonstrând tiparul fork-and-wait
Iată ideea de bază
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
void ruleaza_comanda(const char *comanda) {
pid_t pid = fork();
if (pid == 0) {
// Copilul: executa comanda
if (strcmp(comanda, "salut") == 0) {
printf("Salut din laborator!\n");
} else if (strcmp(comanda, "data") == 0) {
printf("1974\n");
} else {
printf("Comanda necunoscuta: %s\n", comanda);
}
fflush(stdout); // scrie bufferul inainte sa iesim
_exit(0); // copilul iese
} else {
// Parintele: asteapta copilul
wait(NULL);
printf("Gata\n");
fflush(stdout); // la fel, golim bufferul aici
}
}
int main(void) {
ruleaza_comanda("salut");
ruleaza_comanda("data");
ruleaza_comanda("necunoscuta");
return 0;
}
_exit(0) este ca return 0, dar pentru procesele copil după fork: iese imediat, fără curățenie suplimentară care ar putea încurca părintele. Are însă un efect secundar: nu golește bufferul lui printf, așa că trebuie să chemăm fflush(stdout) noi înșine, chiar înainte de _exit, ca textul să ajungă cu adevărat pe teletype
wait(NULL) îl blochează pe părinte până când copilul termină. Nu ne interesează codul de ieșire exact, doar faptul că a terminat
Părintele creează câte un copil pentru fiecare comandă, așteaptă să termine, apoi trece la următoarea. Exact așa funcționează un shell, simplificat. Fiecare comandă rulează în izolare: dacă un copil crapă, părintele supraviețuiește și merge mai departe
Misiune: Terminalul de comenzi al laboratorului
Ești operator de noapte la centrul de calcul. Un teletype din laborator îți trimite, pe rând, comenzi de rulat. Fiecare comandă trebuie procesată de un proces copil separat, ca laboratorul să nu cadă dacă una dintre ele eșuează. Coada de comenzi se termină mereu cu cuvântul "iesire"
Scrie un program care
-
Citește cuvinte din input, unul câte unul, cu scanf("%s", ...), într-o buclă
-
Dacă tocmai ai citit "iesire", oprește bucla imediat, fără să mai apelezi ruleaza_comanda
-
Altfel, apelează ruleaza_comanda cu cuvântul citit. Procesul copil verifică șirul și afișează
- "ora" afișează "12:04"
- "spatiu" afișează "128K liber"
- orice altă comandă afișează "Comanda necunoscuta: X", unde X este comanda primită
Nu uita fflush(stdout) înainte de _exit(0), altfel textul afișat de copil se pierde
-
Părintele așteaptă copilul cu wait(NULL), afișează "Gata", apoi golește el însuși bufferul cu fflush(stdout)
Exemplu
Intrare
ora
spatiu
necunoscuta
iesire
Ieșire
12:04
Gata
128K liber
Gata
Comanda necunoscuta: necunoscuta
Gata
Exemplu
Intrare
spatiu
iesire
Ieșire
128K liber
Gata