next up previous contents
Next: Daemon folyamatok Up: Rendszerhívások Previous: Egyéb rendszerhívások

Egy összetettebb példa: a shell

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



Csizmazia Balazs
Tue Apr 2 00:06:27 MET DST 1996