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 ");
}