Ebben a részben egy minimális képességu shell (parancsértelmezo) funkcióit ellátó program forráslistája van. A programon keresztül a UNIX alapvetobb rendszerhívásait ismerhetjük meg (ezért kerültem a szabványos I/O könyvtár használatát, a printf()-et és egyebeket).
A shell foprogramja -- a main() függvénynél ciklusban kiír
egy prompti ($
) karaktert -- ezzel jelezve a felhasználónak, hogy parancsra
vár -- majd beolvas egy sort a szabványos bemenetrol (ami ugye
leggyakrabban a billentyuzetroli olvasást jelenti interaktív
shell-eknél).
Ezután a beadott parancsot a darabol() nevu eljárással
szétszedi részeire, az argstrs nevu paraméterében
megadott tömböt (a benne levo mutatókat)
a beadott parancs egyes komponenseire állítja: az elso (azaz a
nulla indexu) elemet a végrehajtandó parancs nevére állítja,
a következo elemet a végrehajtandó parancs elso
argumentumára állítja, stb. Az egyes parancsneveket/argumentumokat
terminálja a \0
karakterrel.
A szétdarabolás után a foprogramban szül egy gyermek-folyamatot,
ami eloször ellenorzi, hogy az utolsó argumentumban a szabványos
kimenetet akarták-e átirányítani, és ha úgy találja, hogy
azt akarták (vagyis egy >
karakterrel kezdodik), akkor lezárja
az addig érvényes szabványos kimenetet, és megnyit egy új fájlt
(ami a szabványos kimenet helyén, az 1-es fájldeszkriptorral
jön létre, mivel az a legelso szabad fájldeszkriptor -- ne felejtsük el,
hogy a 0-ás fájldeszkriptoron a szabványos bemenetet nem bántottuk,
nem zártuk le, ezért a program ilyen szempontból helyesen
muködik). A gyermek-folyamat ezután végrehajtja az execvp()
rendszerhívással a kívánt programot.
A szülo-folyamat várakozik, amíg a gyermeke befejezodik, majd új parancsot kér. Megjegyezzük, hogy a folyamatok háttérbeli elindíthatósága azt jelenti, hogy ezt a várakozást (a wait() rendszerhívást) ki kellene hagyni, és a gyermek-folyamat halálát jelzo signalt kellene kezelnie a shellünknek.
/* minsh.c * * Egy minimalis shell * A szabvanyos bemenet (standard input) csatornarol olvas programneveket es * program-argumentumokat, es vegrehajtja a megadott programokat a megadott * argumentumokkal. * A szabvanyos kimenet atiranyithato - elegge primitiven: >fajlnev * metakarakterekkel ... mint az igazi shellekben, DE itt ez csak es * kizarolag az utolso argumentumban fordulhat elo, vagyis a parancssor * vegen. */ #include <fcntl.h> #define CBUFSIZE 1024 /* Parancsbuffer merete */ #define NR_ARGSTRS 32 /* Maximalis argumentumszam */ #ifndef NULL #define NULL ((void *)0) #endif void darabol(pbuf,argstrs,argn) char *pbuf; char **argstrs; int *argn; { int pozicioszamlalo=0,pbufhossz; int local_argn; local_argn=0; pbufhossz=strlen(pbuf); while (isspace(pbuf[pozicioszamlalo]) && pozicioszamlalo<pbufhossz) { pbuf[pozicioszamlalo]='\0'; pozicioszamlalo++; } while (pozicioszamlalo < pbufhossz) { argstrs[local_argn]= &pbuf[pozicioszamlalo]; local_argn++; while (!(isspace(pbuf[pozicioszamlalo])) && pozicioszamlalo<pbufhossz) pozicioszamlalo++; while (isspace(pbuf[pozicioszamlalo]) && pozicioszamlalo<pbufhossz) { pbuf[pozicioszamlalo]='\0'; pozicioszamlalo++; }; }; argstrs[local_argn]=NULL; local_argn++; *argn=local_argn; } void main(argc,argv,envp) int argc; char **argv, **envp; { int gy_status; /* A befejezodott gyermekfolyamat allapotarol ad informaciot */ char parancsbuf[CBUFSIZE]; char *argstrings[NR_ARGSTRS]; int argnum,fn,nchars; char *stdoutfnev; do { write(1,"$ ",2); if ((nchars=read(0,parancsbuf,CBUFSIZE)) > 0) { /* -1 hiba, 0 fajlvege */ darabol(parancsbuf,argstrings,&argnum); if (argnum > 1) { /* Ha megadtak valami (vegrehajtando-) fajlnevet */ if (fork() == 0) { fn=1; if ((argnum > 2) && (argstrings[argnum-2][0]=='>')) { stdoutfnev=&(argstrings[argnum-2][1]); /* Ronda, de vilagos ... */ close(1); /* lezarja az ezelotti szabvanyos kimenet fajlt */ fn=creat(stdoutfnev,0744); argstrings[argnum-2]=NULL; argnum=argnum-1; } if (fn == 1) execvp(argstrings[0],argstrings); else perror("Standard kimenet atiranyitasa sikertelen "); perror("execvp nem sikerult "); exit(-1); /* Hiba - execvp sikertelen */ } else { wait(&gy_status); /* szulo var */ } } } } while (nchars != 0); if (nchars == (-1)) perror(" hiba a standard input olvasasakor "); }