Írjunk shellt

Egy érdekes feladatot fogalmaztak meg a következőképpen: írjunk egy shell-szerű programot, mely bemutatja, hogy hogyan kezeli a Unix a folyamatokat (processeket). A program saját parancsbekérővel rendelkezzen, miután beolvasta a billentyűzetről a parancsot, hajtassa végre az operációs rendszerrel, majd várjon új parancsra. Nem szabad használni a "system" parancsot, illetve a popen könyvtár parancsait, ezek helyett használjuk a fork, a dup2 illetve az exec családot.

A következő követelményeknek kell eleget tennie:

  1. Első lépésként a mini shell csak a paraméter nélküli parancsokat tudja kezelni, mint például ls vagy date
  2. A második lépcsőfok az legyen, hogy tudjunk paramétereket is átadni a shellnek, mint például: ls –l –tmp vagy more filename, netán gcc –s –O –g –o testing foo.c stb.
  3. A harmadik szint a shellben az legyen, hogy alapfokú olvasási átirányításokat tudjon kezelni. A program pásztázza végig a beérkező utasítást, és ha talál benne egy kisebb (<) jelet, akkor az utána következő szót értelmezze úgy, mint egy bemenő adatokat tartalmazó fájl, és bármilyen olvasási műveletet akar a parancs végrehajtani, az a megadott fájlból történjen meg, ne pedig a billentyűzetről. Ha ez a fájl nem létezik, hibaüzenet visszaadása javallott. Amennyiben egynél több paramétert adtak meg a < jel után, az hibának minősül, és a shellnek ezt vissza kell jeleznie a felhasználó felé. Például helyes: wc < datafile illetve helytelen: ls < datafile foo.
  4. A következő alapvető tulajdonság az írás átirányításnak kell lennie. A shell pásztázza végig a beérkező utasítást, és ha talál benne egy nagyobb (>) jelet, akkor a parancs kimenetét átirányítsa át a > jel után megadott fájl névre ahelyett,  hogy a képernyőre írná ki. Ha az állományt nem tudja létrehozni, egy hibaüzenetet kell generálni, és a parancsot nem szabad végrehajtani. Amennyiben egynél több paramétert adtak meg a > jel után, az hibának minősül, és a shellnek ezt vissza kell jeleznie a felhasználónak. Helyes például: ls > datafile vagy ps –augx > file, illetve helytelen: ls < datafile foo.
  5. Engedélyezzük a mini shellnek a környezeti változókhoz való hozzáférést, illetve ezeknek módosítását. A shellnek kell értelmeznie a következő parancsokat: set, print. Ezeknek a formátuma a következő: setenv var=value illetve printenv var. A setenv parancsnál nincs szóköz az egyenlőségjel egyik oldalán sem. Ajánlott olvasmány: a getenv, putenv illetve environ man oldala, különös figyelemmel olvassák el az apró betűs részt a putenv parancsnál.
  6. A shell legyen képes végrehajtani a leghétköznapibb parancsokat, mint például: a cd, a  path (könyvtárváltáshoz), vagy az echo kiiratando (kiirja a kiiratando-t) illetve az exit parancs, amivel kilépünk a shellből.
  7. Végül az egészet egybeolvasztva hozzunk létre olyan shellt, ami tartalmazza az összes eddig említett tulajdonságot. Nem kötelező viszont a környezeti változókkal való műveletek I/O átirányítása.

Megoldás

#include <sys/types.h>

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <string.h>

#include <sys/wait.h>

#include <errno.h>

 

int otodik(char* p, char *sz)

{

int n,rossz,I,josor,j;

int merre=1;

      if (strcmp(p,”echo”)==0)

      {

            if(sz[0]==’”’)

            {

                  sz[0]=’ ‘;

                  n=strlen(sz);

                  sz[n-1]=’\0’;

            } //if

            printf(“%s\n”,sz);

      } //if echo

 

      if (strcmp(p,”cd”)==0)

      {

            if ( chdir(sz) < 0)

                        {

                  printf(“Nem tudom a konyvtarvaltast vegrehajtani\n”);

                        }

      }//if chdir

 

      if(strcmp(p,”setenv”)==0)

      {

            n=strlen(sz);

                        rossz=0;

                        josor=0;

            I=0;

            while((rossz==0)&&(I<n))

            {

                  if(sz[I]==’ ‘) rossz=1;

                  I++;

            } //while

            for(j=0;j<n;j++) if (sz[j]==’=’)

            {

                  josor++;

                        }

            if((rossz==0)&&(josor==1))

                        {

                  putenv(sz);

                        }

            else

            {

                  if (rossz!=0)

                  {

                        printf(“Hibas a parancssor!\n”);

                                    }

                  else

                                    {

                        printf(“Igy nem valosithato meg kornyezeti \                                                                               valtozo beallitasa\n”);

                                    }

                        }

      } // if setenv

 

      if(strcmp(p,”printenv”)==0)

      {

            n=strlen(sz);

            rossz=0;

            for (I=0; I<n; I++)

                        {

                  if (sz[I]==’ ‘)

                  {

                        rossz=1;

                        printf(“Rosszul adtad meg a kornyezeti\                                                                                         valtozot\n”);

                  }

                        }

 

            if(rossz!=1)

                        {

                  if (getenv(sz)!=’\0’)

                  {

                        printf(“%s\n”,getenv(sz));

                                    }

                  else

                                    {

                        printf(“Nincs ilyen kornyezeti valtozo!\n”);

                                    }

      } //if printenv

 

      return(merre);

}

 

int  masodik(char sz[])

{

char b,szo;

char *a[10];

int j,k,I,l;

int allj;

            allj=0;

            I=0;

            j=0;

      while (sz[I]!=’\0’)

      {

                        k=0;

            szo=(char *)malloc(30);

            while ((sz[I]!=’ ‘) && (sz[I]!=’\0’))

            {

                  szo[k]=sz[I];

                  k++;

            I++;

            } //while szorabontas

            szo[k]=’\0’;

            if (sz[I]!=’\0’)

            {

                  I++;

                        }

            if (j==0)

            {

                  b=szo;

                        }

            a[j]=szo;

            j++;

      } //while sorvegeig

 

      a[j]=(char *)0;

      execvp(b,a);

      printf(“hiba\n”);

      return(allj);

}

 

void harmadik (char* fnev,char sz[])

{

int f;

      f=open(fnev,O_RDONLY);

      if (f!=-1)

      {

            dup2(f,STDIN_FILENO);

            masodik(sz);

      }

      else

            {

            printf(“Nem sikerult a file megnyitasa, talan nem letezik\                                                   vagy nincs jogod hozza...\n”);

            }

}

 

void negyedik (char fnev[20], char sz[])

{

int fd;

 

      if ((fd=open(fnev,O_CREAT|O_RDWR|O_TRUNC,0666))<0)

      {

            printf(“%s\n”,strerror(errno));

      }

 

      if (fd!=-1)

      {

            dup2(fd,STDOUT_FILENO);

            masodik(sz);

      }

            else

      {

            printf(“Nem sikerult a file megnyitasa!\n”);

            }

}

 

int tovabbmehet (char sz[])

{

char parancs[20],uj[20];

int I,k;

int allj=0;

            I=0;

      while ((sz[I]!=’ ‘) &&(sz[I]!=’\0’))

      {

            parancs[I]=sz[I];

            I++;

      }

      parancs[I]=’\0’;

      if ( (strcmp(parancs,”echo”)==0)||

             (strcmp(parancs,”cd”)==0) ||

             (strcmp(parancs,”setenv”)==0) ||

             (strcmp(parancs,”printenv”)==0))

      {

            k=0;

            if (sz[I]!=’\0’)

            {

                  I++;

                  while (sz[I]!=’\0’)

                  {

                        uj[k]=sz[I];

                        k++;I++;

                  }

            }

            uj[k]=’\0’;

            allj=otodik(parancs,uj);

      }

      return(allj);

}

 

int ellenoriz (char sz[], int I, int milyen)

{

int j,l;

char fil[20],*uj;

int vegjel,k;

      vegjel=0;

      j=I;

      I++;

      while ((sz[I]!=’\0’)&&(vegjel==0))

      {

            k=0;

            while((sz[I]!=’ ‘)&&(sz[I]!=’\0’))

            {

                  fil[k++]=sz[I];

                  I++;

            } // while belso

            fil[k]=’\0’;

            if (sz[I]==’\0’)

            {

                  for(l=0;l<j;l++)

                                    {

                        uj[l]=sz[l];

                                    }

                  uj[l-2]=’\0’;

                  if (milyen==1)   

                  {

                        harmadik(fil, uj);

                  }

                                    else

                  if (milyen==2)

                  {

                                                negyedik(fil,uj);

                                    }

                  vegjel=1;

            } //if utolso parancs

            else

            {

                  I++;

                  if (sz[I]==’<’)

                  {

                        vegjel=2;

                  }

                  else

                  {

                        printf (“Nem adhatsz meg ket filenevet!\n”);

                                                exit(0);

                  }

            } //else

      } //while

      return(0);

};

 

void szetszed(char sz[])

{

int I, van;

van=0;

I=0;

      while ((van==0)&&(sz[I]!=’\0’))

      {

            if (sz[I]==’>’)

            {

                  van=2;

                        }

            else

            {

                  if (sz[I]==’<’)

                  {

                        van=1;

                                    }

        }

            I++;

      } //while

      if (van==0)

      {

            masodik(sz);

            }

      if (van==2)

      {

            ellenoriz(sz,I,van);

            }

      if (van==1)

      {

            ellenoriz(sz,I,van);

            }

}

 

 

int main(int argc, char *argv[])

{

char s[100];

pid_t pid;

int merre;

      printf(“> “);

      while (fgets (s,100,stdin)!=NULL)

      {

            s[strlen(s)-1]=0;

            if (strcmp(s,”exit”)==0)

            {

                  (s,100,stdin)=NULL;

                  exit(0);

            } //if

            merre=tovabbmehet(s);

            if (merre==0)

            {

                  if ((pid=fork())<0)

                  {

                        printf(“Fork hiba\n”);

                                    }

                  else

                  if (pid==0)

                  {

                        execlp(s,s,NULL);

                        szetszed(s);

                        printf (“ez meg tul komplikalt nekem nem tudom\                                                                                     vegrehajtaniL((\n”);

                        exit(0);

                  }

                  if ((pid=waitpid(pid,NULL,0))<0)

                                    {

                        printf(“waitpid hiba\n”);

                                    }

            } // if merre

            printf(“> “);

      }

      exit(0);

}

 

A következő számban kiderül, hogy mi miért alakult így ... 

 

Finta Annamária