Universidade Federal de Ouro Preto


 Instituto de Ciências Exatas e Biológicas


      Departamento de Computação




BCC264 - Sistemas Operacionais
      Terceiro Trabalho Prático




            Johnnatan Messias
           Pollyanna Gonçalves
            Wellington Dores


     Professor - Fabrício Benevenuto




               Ouro Preto
           1 de junho de 2011
Sumário

1   Introdução                                                                                                                     1
    1.1 Considerações iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . .                                               1
    1.2 O Problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                 1
        1.2.1 Linguagem da MyShell . . . . . . . . . . . . . . . . . . . . . .                                                     1

2   A implementação da MyShell                                                                                                     2
    2.1    Tratamento da Entrada de dados . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    3
    2.2    Função para comando Ls . . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    3
    2.3    Função para comando Pwd . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
    2.4    Função para comando Cd . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
    2.5    Função para comando Cat . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
    2.6    Função para comando Grep . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
    2.7    Função para comando Ping . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
    2.8    Função para comando Kill . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
    2.9    Função para comando Date . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    7
    2.10   Função para comando Mkdir . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    7
    2.11   Função para comandos Mv, Rm e RmDir .                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    8
    2.12   Função para comando Cp . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
    2.13   Função para comando Chmod . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
    2.14   Função para comando Ps . . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
    2.15   Função para comando Sh e Bash . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   10
    2.16   Função para comando Sleep . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
    2.17   Função para comando Pipe e Background .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
    2.18   Função para comando Exit . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
    2.19   Função Principal . . . . . . . . . . . . . .                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   12


Lista de Programas

    1      Função split . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    3
    2      Função ls . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    3
    3      Função pwd . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
    4      Função cd . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
    5      Função cat . . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
    6      Função grep . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
    7      Função ping . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
    8      Função kill . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
    9      Função date . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    7
    10     Função mkdir . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    7
    11     Funções Rm, Mv e RmDir . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    8
    12     Função cp . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
    13     Função chmod . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
    14     Função ps . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
    15     Funções Sh e Bash . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   10
    16     Função sleep . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
    17     Função Pipe ( )eBackground(&)           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
    18     Função Exit . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   12

                                              2
19   Função Main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12




                                     3
1       Introdução

   Este trabalho tem por objetivo fazer com que os alunos se familiarizem com o
ambiente Unix, desenvolvam habilidades de programação defensiva em C, aumentem
sua exposição às funcionalidades de interpretadores de comandos e coloquem em
prática conceitos sobre gerência de processos (p.ex., disparo e terminação).

1.1      Considerações iniciais

    • Sistema Operacional utilizado: Ubuntu 11.04

    • Ambiente de desenvolvimento: NetBeans IDE C/C++

    • Ambiente de desenvolvimento da documentação: TeXnicCenter 1 Editor de
        LTEX.
        A



1.2      O Problema

   Implementar uma shell mínima, a M yShell, para colocar em prática os princípios
de manipulação de processos. Esse tipo de conhecimento é essencial no desenvolvi-
mento de sistemas complexos com diversos processos, como no caso de servidores.

1.2.1     Linguagem da MyShell

    A linguagem compreendida pela M yShell é bem simples. Cada sequência de
caracteres diferentes de espaço é considerada um termo. Termos podem ser oper-
ações internas da shell, nomes de programas que devem ser executados, argumentos
a serem passados para os comandos ou programas e operadores especiais. Oper-
ações internas da shell são as sequências de caracteres cd, pwd, wait e exit. Essas
operações devem sempre terminar com um sinal de m de linha (return) e devem
ser entradas logo em seguida ao prompt (isto é, devem sempre ser entrados como
linhas separadas de quaisquer outros comandos). Operadores são os símbolos (back-
ground) e | (pipe), quando ocorrem isoladamente (como um único caractere entre
espaços). Programas a serem executados são identicados pelo nome do seu ar-
quivo executável e podem ser seguidos por um número máximo de dez argumentos
(parâmetros que serão passados ao programa através do vetor argv[]. Cada comando
de disparo deve terminar com um dos operadores, ou com o m de linha.

    • Fim de linha: indica que o processo deve ser disparado e a myshell deve esperar
        pelo seu m antes de exibir outro prompt.
    • Background: o processo deve ser disparado e a M yShell deve continuar sua
        execução. Isso pode signicar a continuação da interpretação da linha de co-
        mandos, se há outros comandos na linha, ou o retorno imediato ao prompt.
        Cada vez que um processo é disparado em background, M yShell deve ex-
        ibir uma mensagem a esse respeito, com o identicador (pid) do processo em
        questão.
    • Pipe: o conteúdo após o operador deve ser interpretado outro comando a ser
        executado, sendo que a saída padrão do primeiro processo deve ser conectada

                                          1
à entrada padrão do processo seguinte. Para simplicar a implementação,
      M yShell não permite o encadeamento de pipes, isto é, não é permitido colo-
      car outro pipe na saída do segundo programa. Pode-se, entretanto, colocar
      ambos os programas em background terminando a sequência com o operador
      apropriado (nesse caso, uma mensagem sobre a operação em background deve
      ser exibida para cada processo).
    Os comandos internos têm as seguintes interpretações:
    • CD: muda o diretório corrente da shell. Isso terá impacto sobre os arquivos
      visíveis sem um caminho completo (path).
    • PWD: exibe o diretório corrente visto pelo processo.
    • WAIT: faz com que a shell espere pelo término de todos os processos que
      possam estare m execução antes de exibir um novo prompt. Cada processo
      que seja encontrado durante um wait deve ser informado através de uma men-
      sagem na linha de comando. Caso não haja processos pelos quais esperar, uma
      mensagem a respeito deve ser exibida e M yShell deve continuar sua execução.
    • EXIT: termina a operação da shell se não há processos em background. Caso
      contrário, exibe uma mensagem informando o fato e realiza a operação wait
      antes de terminar.


2     A implementação da MyShell

    Mais adiante apresentamos a implementação das funções que trata um comando
qualquer que vai ser digitado pelo usuário na M yShell, algumas das funções primi-
tivas que serão utilizadas em outras funções estão explicadas abaixo:
    • Primitiva f ork(): única chamada de sistema que possibilita a criação de um
      processo em U N IX .
    • Primitiva execv(): função em que o primeiro argumento corresponde ao cam-
      inho completo para o executável ou script a ser executado e o segundo é o
      nome do programa a ser executado.
    • Primitiva wait(): suspende a execução do processo pai até a morte de seu
      processo lho (se o lho já estiver morto, a função retorna -1, imediatamente).
    • Primitiva exit(): ADICIONAR!!!!
   Algumas bibliotecas da linguagem C que foram utilizadas para a execução do
programa:
    • errno.h
    • signal.h
    • sys/types.h
    • sys/wait.h
    • unistd.h

                                         2
2.1           Tratamento da Entrada de dados

        A função split, representada abaixo, trata a entrada de dados do usuário na
     M yShell utilizando funções auxiliares da biblioteca string.h denidas na linguagem.
     1
     char ∗∗        split (             char ∗∗            linha ,     char ∗∗               vString ,             char ∗∗   comando ,   int ∗   tam ) {



          char ∗
          int
                              tok        = NULL ;



                                  char ∗                             sizeof char
                      i ;

 5            tok    =        (                 )    malloc (                        (                )     ∗200) ;
              s t r c p y ( tok ,             ∗ linha ) ;
              tok    =        s t r t o k ( tok ,  n ) ;

              ∗ comando                 =    s t r t o k ( tok ,          ) ;


10
              // P o s i ç ã o           0      reservada             para       o       execv
              vString [ 1 ]                 =       s t r t o k (NULL,              ) ;


              if   ( ! vString [ 0 ] )

15                    vString [ 0 ]                    =       ;


              for   ( i     =       2;       vString [ i         −1];      i ++){

                      vString [ i ]                    =    s t r t o k (NULL,                      ) ;
              }

20


              vString [ i                −      1]     = NULL ;

              ∗ tam       =       ( i    −      1) ;



              return
              f r e e ( tok ) ;

25                                vString ;

     }


                                                                  Programa 1: Função split


     2.2           Função para comando Ls

         O comando ls, em U N IX , mostra o conteúdo de um diretório passado como
     argumento. A função abaixo implementada recebe como parâmetro (em forma de
     string ) os argumentos que foram passados pelo usuário da M yShell: 2
     void         meu_ls (         char ∗∗             vArgumentos )

     {




              int
              vArgumentos [ 0 ]                        =    / b i n / l s  ;
 5                    pid_cd                =       fork () ;



         if       ( pid_cd ==                   0)



              else
                      execv ( / b i n / l s  ,                     vArgumentos ) ;



10
                      int
         {

                                    status1 ;

                      w a i t ( s t a t u s 1 ) ;               // e s p e r a          a       morte        de    um   filho
              }

     }


                                                                     Programa 2: Função ls


                                                                                                 3
2.3              Função para comando Pwd

       O comando pwd, em U N IX , apresenta o diretório corrente do usuário da M yShell.
     Uma implementação para essa função é apresentada em: 3
     void            meu_pwd (         char ∗∗       vArgumentos )

         {



                 vArgumentos [ 0 ]                  =    / b i n / pwd  ;
 5
                 int       pid     =     fork () ;



                 if       ( pid    ==     0)

             {

10                         p r i n t f (  n ) ;

                           e x e c v (  / b i n / pwd  ,      vArgumentos ) ;

                           p r i n t f (  n ) ;




             else
                 }

15


                           int
             {

                                   status1 ;

                           w a i t ( s t a t u s 1 ) ;

                 }

20   }


                                                              Programa 3: Função pwd


     2.4              Função para comando Cd

        O comando cd, em U N IX , abre o diretório passado como argumento pelo usuário
     da M yShell. Uma implementação para essa função é apresentada em: 4
     void            meu_cd (      char ∗∗          vArgumentos )

         {



                 int       pid_cd         =    0;

 5
                 if       ( pid_cd ==           0)



                           char
             {

                                       cwd [ 2 0 4 8 ] ;

                           cwd [ 0 ]      =    ' 0 ' ;
10
                           if     ( g e t c w d ( cwd ,      2048)      !=    NULL)



                                    if
                 {

                                          ( c h d i r ( vArgumentos [ 1 ] )           !=   0)

                      {

15                                            printf ( It        wasn ' t     possible         set   current   directory   to   / n
                                                    ) ;
                                   }

                           }




             else
                 }

20


                           int
             {

                                   status1 ;

                           w a i t ( s t a t u s 1 ) ;

                 }




                                                                                4
25   }


                                                      Programa 4: Função cd
        Para a implementação dessa função utilizamos as funções getcwd() (retorna o
     nome completo do diretório corrente) e chdir (muda o diretório corrente para aquele
     passado como parâmetro).

     2.5          Função para comando Cat

         O comando cat, em U N IX , combina um ou mais arquivos e os apresenta na
     saída padrão, ou seja, mostra o conteúdo de um arquivo passado como argumento
     pelo usuário da M yShell. Uma implementação para essa função é apresentada em:
     5
     void        meu_cat (   char ∗∗      vArgumentos )

     {



             vArgumentos [ 0 ]          =     / b i n / c a t  ;
 5
             int    pid_cat       =    fork () ;



             if    ( pid_cat      ==     0)



             else
                    execv ( / b i n / c a t  ,       vArgumentos ) ;

10


                    int
         {

                           status1 ;

                    w a i t ( s t a t u s 1 ) ;

             }

15   }


                                                     Programa 5: Função cat


     2.6          Função para comando Grep

        O comando cat, em U N IX , procura por linhas em arquivos que correspondam
     a um padrão especicado pelo usuário da M yShell e as apresenta. Uma implemen-
     tação para essa função é apresentada em: 6
     void        meu_grep (    char ∗∗        vArgumentos )

     {




             int
             vArgumentos [ 0 ]          =     / b i n / grep  ;
 5
             if
                    pid    =    fork () ;

                   ( pid   ==    0)

         {

                    p r i n t f (  n ) ;

                    execv ( / b i n / grep  ,          vArgumentos ) ;

10                  p r i n t f (  n ) ;




         else
             }




                    int
         {

15                         status1 ;

                    w a i t ( s t a t u s 1 ) ;

             }




                                                                     5
}


                                                            Programa 6: Função grep


     2.7              Função para comando Ping

        O comando ping , em U N IX , envia pacotes ICM P para um determinado host
     e mede o tempo de resposta. Uma implementação para essa função é apresentada
     em: 7
     void            meu_ping (        char ∗∗        vArgumentos )

     {




                 int
                 vArgumentos [ 0 ]              =     / b i n / ping  ;
 5
                 if
                            pid    =   fork () ;

                       ( pid      ==     0)

             {

                            p r i n t f (  n ) ;

                            execv ( / b i n / ping  ,          vArgumentos ) ;

10                          p r i n t f (  n ) ;




             else
                 }




                            int
             {

15                                 status1 ;

                            w a i t ( s t a t u s 1 ) ;

                 }

     }


                                                            Programa 7: Função ping


     2.8              Função para comando Kill

         O comando kill, em U N IX , envia sinais a determinados processos em execução.
     Por padrão é enviado o sinal SIGT ERM que requisita a nalização de um processo.
     Em geral é utilizado na forma 1 , onde pid é o identicador do processo que pode
     ser obtido através do comando ps 14. Uma implementação para essa função é
     apresentada em: 8
     void            meu_kill (        char ∗∗        vArgumentos )

         {




                 int
                 vArgumentos [ 0 ]              =     / b i n / k i l l  ;
 5
                 if
                            pid    =   fork () ;

                       ( pid      ==     0)

             {

                            p r i n t f (  n ) ;

                            execv ( / b i n / k i l l  ,       vArgumentos ) ;

10                          p r i n t f (  n ) ;




             else
                 }




                            int
             {

15                                 status1 ;


             1 kill   pid




                                                                               6
w a i t ( s t a t u s 1 ) ;

             }

     }


                                                     Programa 8: Função kill


     2.9          Função para comando Date

        O comando date, em U N IX , simplesmente exibe a data e a hora atual do sistema
     no prompt da M yShell. Uma implementação para essa função é apresentada em:
     9
     void        meu_date (    char ∗∗        vArgumentos )

     {




             int
             vArgumentos [ 0 ]          =     / b i n / d a t e  ;
 5
             if
                    pid    =    fork () ;

                   ( pid   ==    0)

         {

                    p r i n t f (  n ) ;

                    execv ( / b i n / d a t e  ,       vArgumentos ) ;

10                  p r i n t f (  n ) ;




         else
             }




                    int
         {

15                         status1 ;

                    w a i t ( s t a t u s 1 ) ;

             }

     }


                                                    Programa 9: Função date


     2.10          Função para comando Mkdir

       O comando mkdir, em U N IX , cria um diretório no diretório atual da M yShell.
     Uma implementação para essa função é apresentada em: 10
     void        meu_mkdir (     char ∗∗       vArgumentos )

     {




             int
             vArgumentos [ 0 ]          =     / b i n / mkdir  ;
 5
             if
                    pid    =    fork () ;

                   ( pid   ==    0)

         {

                    p r i n t f (  n ) ;

                    execv ( / b i n / mkdir  ,           vArgumentos ) ;

10                  p r i n t f (  n ) ;




         else
             }




                    int
         {

15                         status1 ;

                    w a i t ( s t a t u s 1 ) ;

             }

     }




                                                                       7
Programa 10: Função mkdir


     2.11         Função para comandos Mv, Rm e RmDir

        Os comandos mv , rm e rmdir, em U N IX , move (ou renomeia) um diretório ou
     cheiro, remove um determinado cheiro e um remove um diretório, respectivamente.
     Uma implementação para essa função é apresentada em: 11
     void    meu_mv(          char ∗∗       vArgumentos )        {




            int
            vArgumentos [ 0 ]           =      / b i n /mv ;


            if
                   pid     =    fork () ;

 5                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   e x e c v (  / b i n /mv ,     vArgumentos ) ;

                   p r i n t f (  n ) ;



10               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }

15
     void       meu_rm (      char ∗∗       vArgumentos )        {




            int
            vArgumentos [ 0 ]           =      / b i n /rm ;


            if
                   pid     =    fork () ;

20                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   e x e c v (  / b i n /rm ,     vArgumentos ) ;

                   p r i n t f (  n ) ;



25               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }

30


     void       meu_rmdir (      char ∗∗       vArgumentos )         {




            int
            vArgumentos [ 0 ]           =     / b i n / rmdir  ;
35
            if
                   pid     =    fork () ;

                  ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   execv ( / b i n / rmdir  ,          vArgumentos ) ;

                   p r i n t f (  n ) ;

40
                 else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

45   }


                                        Programa 11: Funções Rm, Mv e RmDir


                                                                     8
2.12         Função para comando Cp

        O comando cp, em U N IX , permite que o usuário faça cópia de um cheiro para
     outro, onde o primeiro cheiro (passado como argumento) é lido e copiado para o
     segundo (no caso da inexistência desse, o mesmo é criado). Uma implementação
     para essa função é apresentada em: 12
     void       meu_cp (      char ∗∗       vArgumentos )         {




            int
            vArgumentos [ 0 ]           =     / b i n / cp  ;


            if
                   pid     =    fork () ;

 5                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   e x e c v ( / b i n / cp  ,     vArgumentos ) ;

                   p r i n t f (  n ) ;



10               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }


                                                    Programa 12: Função cp


     2.13         Função para comando Chmod

         O comando chmod, em U N IX , permite que o usuário altere as permissões de
     um cheiro ou diretório no formato drwxrwxrwx, respectivamente: diretório (d),
     permissão do dono (read/write/execute), do grupo (read/write/execute) e de outros
     (read/write/execute). Uma implementação para essa função é apresentada em: 13
     void       meu_chmod (      char ∗∗       vArgumentos )          {




            int
            vArgumentos [ 0 ]           =      / b i n / chmod  ;


            if
                   pid     =    fork () ;

 5                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   e x e c v (  / b i n / chmod  ,      vArgumentos ) ;

                   p r i n t f (  n ) ;



10               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }


                                                  Programa 13: Função chmod


     2.14         Função para comando Ps

         O comando ps, em U N IX , lista a lista de processos em execução, geralmente
     utilizado quando se necessita para saber o pid de um processo terminá-lo com o
     comando kill. Uma implementação para essa função é apresentada em: 14
     void       meu_ps (      char ∗∗       vArgumentos )         {




                                                                      9
int
            vArgumentos [ 0 ]           =     / b i n / ps  ;


            if
                   pid     =    fork () ;

 5                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   execv ( / b i n / ps  ,         vArgumentos ) ;

                   p r i n t f (  n ) ;



10               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }


                                                    Programa 14: Função ps


     2.15         Função para comando Sh e Bash

         Os comandos sh e bash, em U N IX , são interpretadores de comandos feitos para
     intermediar o usuário e seu sistema. Através deles, o usuário manda um comando,
     e o interpretador o executa no sistema. Eles são a shelldo sistema. Uma imple-
     mentação para essa função é apresentada em: 15
     void       meu_sh (      char ∗∗       vArgumentos )         {




            int
            vArgumentos [ 0 ]           =     / b i n / sh  ;


            if
                   pid     =    fork () ;

 5                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   execv ( / b i n / sh  ,         vArgumentos ) ;

                   p r i n t f (  n ) ;



10               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }

15
     void       meu_bash (      char ∗∗       vArgumentos )           {




            int
            vArgumentos [ 0 ]           =     / b i n / bash  ;


            if
                   pid     =    fork () ;

20                ( pid   ==     0)     {

                   p r i n t f (  n ) ;

                   execv ( / b i n / bash  ,          vArgumentos ) ;

                   p r i n t f (  n ) ;



25               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }


                                              Programa 15: Funções Sh e Bash




                                                                      10
2.16         Função para comando Sleep

        O comando sleep, em U N IX , é usado para dar um tempo antes de começar um
     novo processo pela M yShell. Uma implementação para essa função é apresentada
     em: 16
     void       meu_sleep (      char ∗∗         vArgumentos )                {




            int
            vArgumentos [ 0 ]           =       / b i n / s l e e p  ;


            if
                   pid     =    fork () ;

 5                ( pid    ==    0)    {

                   p r i n t f (  n ) ;

                   execv ( / b i n / s l e e p  ,           vArgumentos ) ;

                   p r i n t f (  n ) ;



10               else
                   int
            }             {

                              status1 ;

                   w a i t ( s t a t u s 1 ) ;

            }

     }


                                                     Programa 16: Função sleep


     2.17         Função para comando Pipe e Background

         O comando (pipe), em U N IX , que faz o encadeamento de processosou
     seja, ele permite que a saída de um comando seja diretamente utilizado em outro
     comando. Já o comando  (background) permite que um processo seja executado
     em segundo plano, ou seja, a M yShell não cará impedida de inicializar outros
     processos durante a execução do anterior. Uma implementação para essas funções
     é apresentada em: 17
     int    isPipeOrBk (         char ∗         linha ){



            int    i ,    tam =       strlen ( linha )              −    1;



 5          for
                   if
                  ( i =0;      i  tam ;        i ++)



                              return
                         (( linha [ i ]         ==    '| ')    ||       ( linha [ i ]   ==   ' ' ) ) {
                                           1;



            return
                   }

                          0;

10   }


                                 Programa 17: Função Pipe ( )eBackground()
         Ao receber o comando do usuário utilizamos a função isP ipeOrBk para vericar
     em O(n) se o comando contém ou não os caracteres  ou . Caso tenha, a função
     retornará 1 e 0 caso contrário.

     2.18         Função para comando Exit

         O comando exit, em U N IX , termina a execução da M yShell se não há processos
     em background, caso contrário a ação deverá ser tratada. Uma implementação para
     essa função é apresentada em: 18


                                                                           11
void             meu_cat (          char ∗∗            vArgumentos )

     {



                  vArgumentos [ 0 ]                        =    / b i n / c a t  ;
 5
                  int     pid_cat              =       fork () ;



                  if    ( pid_cat              ==          0)



                  else
                          execv ( / b i n / c a t  ,                      vArgumentos ) ;

10


                          int
             {

                                     status1 ;

                          w a i t ( s t a t u s 1 ) ;

                  }

15   }


                                                                      Programa 18: Função Exit


     2.19               Função Principal

        Abaixo apresentamos a função principal para o funcionamento da M yShell. No
     corpo da função principal main é feita a entrada dos dados pelo usuário (comandos
     e argumentos para tais) e o tratamento de cada caso, chamando as respectivas
     funções que tratam o comando necessitado e ao nal desaloca a memória utilizada
     na execução do programa. A implementação da função é apresentada abaixo: 19
     /   ∗       Mini   −i n t e r p r e t a d o r ∗/

     #include               s t d i o . h



 5   #include               s t d l i b . h



     #include               s t r i n g . h



     #include               u n i s t d . h

10
     #include               f u n c o e s . h


     int        int                                        char       ∗∗ a r g v )
         int
                  main (                 argc ,                                        {

                          linesize                 =       512;       // Tamanho            da     linha         de         comando
15
         char ∗
         char ∗∗
                                linha          = NULL ;               //     Linha         de    Comando


         int
                                 vArgumentos                        = NULL ;         //     Vetor          de    argumentos


         char ∗
                          tam =           0;       //          Quantidade            de     Argumentos


         int
                                comando = NULL ;                            //   Comando           a   ser          executado
20                        i ,       linhaMatriz                     =   40 ,     colunaMatriz                   =       100;         //   dimensoes   do   vetor


         int
                         de     argumentos


                                         char ∗                              sizeof char ∗
                          pos ;



                                                           char ∗ ∗                 sizeof char ∗
                  linha         =    (                 )       malloc (                     (          )        512) ;

                                                                                                                                     ∗ linhaMatriz ) ;
                                                              char ∗                  sizeof char
                  vArgumentos                  =       (                )    malloc (                       (                )

                  vArgumentos [ 0 ]                        =    (            )   malloc (                           (            )     ∗( linhaMatriz ∗

                  for
                         colunaMatriz ) ) ;

25                        ( i   =        1;    i              linhaMatriz ;               i ++)

                          vArgumentos [ i ]                         = ( v A r g u m e n t o s [ 0 ] [ i                ∗   colunaMatriz ] ) ;




                                                                                            12
p r i n t f (  nMYSHELL                 : ) n ) ;
30
         p r i n t f ( DEBUG:           PID %d ,           PPID %d  n  n  ,             getpid () ,                    getppid () ) ;       //    pid   −
                 Process            ID           ppid    −   Parent           Process           ID


         while        (1)     {



35           char           cwd [ 2 0 4 8 ] ;         // P a s t a     atual
                 cwd [ 0 ]     =     ' 0 ' ;


                 if    ( g e t c w d ( cwd ,          2048)       == NULL)             {    //


40                       p e r r o r ( Nao           foi     possivel            obter          o    diretorio                  atual .
                                  Padronizando                para       / n  ) ;
                         s t r c p y ( cwd ,          / ) ;


                         if       ( c h d i r ( cwd )       !=    0)     {



45                                 p e r r o r ( Nÿo           foi     possivel            acessar                   o    diretorio          a t u a l .  n
                                          ) ;



                        }

                 }



50   newline :

                 p r i n t f (  M y S h e l l :~% s $             ,       cwd ) ;



                 f g e t s ( linha ,              linesize ,         stdin ) ;



55               if                                         n  ) == 0 )

                        goto
                       ( strcmp ( l i n h a ,

                                     newline ;            // s e m p r e      que      nÿo          hý       comandos            volta        para
                                  newline


                 if   ( isPipeOrBk ( l i n h a ) ) {



                        continue
                        system ( l i n h a ) ;

60                                            ;

                 }



                 vArgumentos              =        s p l i t ( l i n h a ,     vArgumentos ,                  comando ,            tam ) ;         //
                       Guarda            os       comandos        no     vetor         de    args .


65               //A     partir          desse           ponto       procura           pelo          comando                digitado       e    chama       a
                        funcao           correspondente


                 if    ( strcmp (  h e l p  ,             comando )          ==      0)    {

                        meu_help ( ) ;



70               }    else if          ( strcmp (  c r e d i t o s  ,             comando )             ==           0)    {

                         creditos () ;



                 }    else if          ( strcmp (  l s  ,            comando )           ==        0)    {

                        meu_ls ( v A r g u m e n t o s ) ;

75
                 }    else if          ( strcmp (  e x i t  ,              comando )        ==          0)       {

                        meu_exit ( 0 ) ;



                 }    else if          ( s t r c m p (  pwd  ,         comando )          ==        0)       {

80                      meu_pwd ( v A r g u m e n t o s ) ;




                                                                             13
}    else if     ( strcmp (  cd  ,        comando )   ==   0)       {

             meu_cd ( v A r g u m e n t o s ) ;



 85   }    else if     ( strcmp (  c a t  ,      comando )   ==      0)       {

             meu_cat ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  w a i t  ,      comando )   ==     0)          {

             meu_wait ( ) ;

 90
      }    else if     ( s t r c m p (  ,    comando )   ==    0)    {

             meu_background ( ) ;



      }    else if     ( strcmp (  p i n g  ,      comando )   ==     0) {

 95          meu_ping ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  k i l l  ,      comando )   ==     0) {

             m e u _ k i l l ( vArgumentos ) ;



100   }   else if    ( strcmp (  d a t e  ,      comando )   ==      0) {

             meu_date ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  gr ep  ,        comando )   ==     0) {

             meu_grep ( v A r g u m e n t o s ) ;

105
      }    else if     ( strcmp (  mkdir  ,         comando )    ==       0) {

             meu_mkdir ( v A r g u m e n t o s ) ;



      }    else if     ( s t r c m p ( mv ,     comando )   ==   0) {

110         meu_mv( v A r g u m e n t o s ) ;



      }    else if     ( s t r c m p ( rm ,     comando )   ==   0) {

            meu_rm ( v A r g u m e n t o s ) ;



115   }    else if     ( strcmp (  rmdir  ,         comando )    ==       0) {

             meu_rmdir ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  cp  ,        comando )   ==   0) {

             meu_cp ( v A r g u m e n t o s ) ;

120
      }    else if     ( s t r c m p (  chmod  ,    comando )    ==       0) {

             meu_chmod ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  echo  ,         comando )   ==     0) {

125          meu_echo ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  hostname  ,          comando )      ==             0) {

             meu_hostname ( v A r g u m e n t o s ) ;



130   }    else if     ( strcmp (  ps  ,        comando )   ==   0) {

             meu_ps ( v A r g u m e n t o s ) ;



      }    else if     ( strcmp (  sh  ,        comando )   ==   0) {

             meu_sh ( v A r g u m e n t o s ) ;

135
      }    else if     ( strcmp (  bash  ,         comando )   ==     0) {

             meu_bash ( v A r g u m e n t o s ) ;




                                                     14
}   else if        ( s t r c m p (  nano  ,    comando )   ==   0) {

140                   meu_nano ( v A r g u m e n t o s ) ;



                }   else if        ( strcmp (  s l e e p  ,     comando )   ==   0) {

                      meu_sleep ( vArgumentos ) ;



145             }   else   {

                       p r i n t f ( Comando       '% s '      nÿo   encontrado !       n ,   comando ) ;



                }

                 linha [ 0 ]   =     ' 0 ' ;
150        }

           f r e e ( vArgumentos [ 0 ] ) ;

           f r e e ( vArgumentos ) ;

      }


                                                Programa 19: Função Main
          Aqui é feita a vericação com a função isP ipeOrBk 17 de modo a escolher qual
      será o uxo de execução do programa de duas maneiras:
          • Caso a função isP ipeOrBk retorne 1, ou seja, tendo como instrução a execução
            de um comando em Background ou utilização do Pipe chamamos o comando
            System do Linux para fazer uma chamada ao Sistema de modo a executar
            esses comandos.
          • Caso não haja o programa será executado normalmente de modo que nós é
            que contralamos a criação dos processos lhos e da execução dos comandos
            contidos no
            bin.

          Note que também estamos utilizando uma matriz para guardar os dados que
      serão passados pelo usuário da M yShell. Para essa matriz de char(ou seja, vetor de
      strings) foi feita uma alocação com a quantidade de linhas da matriz de adjacên-
      cias e mais uma alocação para a posição matriz[0] com tamanho Linha ∗ Coluna,
      fazendo, em seguida, um redirecionamento dos endereços da matriz. Para melhor
      entendimento, vide Figura 1




                           Figura 1: Representação da Alocação de Matriz


                                                                 15

MyShell

  • 1.
    Universidade Federal deOuro Preto Instituto de Ciências Exatas e Biológicas Departamento de Computação BCC264 - Sistemas Operacionais Terceiro Trabalho Prático Johnnatan Messias Pollyanna Gonçalves Wellington Dores Professor - Fabrício Benevenuto Ouro Preto 1 de junho de 2011
  • 2.
    Sumário 1 Introdução 1 1.1 Considerações iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 O Problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2.1 Linguagem da MyShell . . . . . . . . . . . . . . . . . . . . . . 1 2 A implementação da MyShell 2 2.1 Tratamento da Entrada de dados . . . . . . . . . . . . . . . . . . . . 3 2.2 Função para comando Ls . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.3 Função para comando Pwd . . . . . . . . . . . . . . . . . . . . . . . . 4 2.4 Função para comando Cd . . . . . . . . . . . . . . . . . . . . . . . . 4 2.5 Função para comando Cat . . . . . . . . . . . . . . . . . . . . . . . . 5 2.6 Função para comando Grep . . . . . . . . . . . . . . . . . . . . . . . 5 2.7 Função para comando Ping . . . . . . . . . . . . . . . . . . . . . . . 6 2.8 Função para comando Kill . . . . . . . . . . . . . . . . . . . . . . . . 6 2.9 Função para comando Date . . . . . . . . . . . . . . . . . . . . . . . 7 2.10 Função para comando Mkdir . . . . . . . . . . . . . . . . . . . . . . . 7 2.11 Função para comandos Mv, Rm e RmDir . . . . . . . . . . . . . . . . 8 2.12 Função para comando Cp . . . . . . . . . . . . . . . . . . . . . . . . 9 2.13 Função para comando Chmod . . . . . . . . . . . . . . . . . . . . . . 9 2.14 Função para comando Ps . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.15 Função para comando Sh e Bash . . . . . . . . . . . . . . . . . . . . 10 2.16 Função para comando Sleep . . . . . . . . . . . . . . . . . . . . . . . 11 2.17 Função para comando Pipe e Background . . . . . . . . . . . . . . . . 11 2.18 Função para comando Exit . . . . . . . . . . . . . . . . . . . . . . . . 11 2.19 Função Principal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Lista de Programas 1 Função split . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2 Função ls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 Função pwd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 Função cd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 5 Função cat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 6 Função grep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 7 Função ping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 8 Função kill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 9 Função date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 10 Função mkdir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 11 Funções Rm, Mv e RmDir . . . . . . . . . . . . . . . . . . . . . . . . 8 12 Função cp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 13 Função chmod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 14 Função ps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 15 Funções Sh e Bash . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 16 Função sleep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 17 Função Pipe ( )eBackground(&) . . . . . . . . . . . . . . . . . . . . 11 18 Função Exit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2
  • 3.
    19 Função Main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3
  • 4.
    1 Introdução Este trabalho tem por objetivo fazer com que os alunos se familiarizem com o ambiente Unix, desenvolvam habilidades de programação defensiva em C, aumentem sua exposição às funcionalidades de interpretadores de comandos e coloquem em prática conceitos sobre gerência de processos (p.ex., disparo e terminação). 1.1 Considerações iniciais • Sistema Operacional utilizado: Ubuntu 11.04 • Ambiente de desenvolvimento: NetBeans IDE C/C++ • Ambiente de desenvolvimento da documentação: TeXnicCenter 1 Editor de LTEX. A 1.2 O Problema Implementar uma shell mínima, a M yShell, para colocar em prática os princípios de manipulação de processos. Esse tipo de conhecimento é essencial no desenvolvi- mento de sistemas complexos com diversos processos, como no caso de servidores. 1.2.1 Linguagem da MyShell A linguagem compreendida pela M yShell é bem simples. Cada sequência de caracteres diferentes de espaço é considerada um termo. Termos podem ser oper- ações internas da shell, nomes de programas que devem ser executados, argumentos a serem passados para os comandos ou programas e operadores especiais. Oper- ações internas da shell são as sequências de caracteres cd, pwd, wait e exit. Essas operações devem sempre terminar com um sinal de m de linha (return) e devem ser entradas logo em seguida ao prompt (isto é, devem sempre ser entrados como linhas separadas de quaisquer outros comandos). Operadores são os símbolos (back- ground) e | (pipe), quando ocorrem isoladamente (como um único caractere entre espaços). Programas a serem executados são identicados pelo nome do seu ar- quivo executável e podem ser seguidos por um número máximo de dez argumentos (parâmetros que serão passados ao programa através do vetor argv[]. Cada comando de disparo deve terminar com um dos operadores, ou com o m de linha. • Fim de linha: indica que o processo deve ser disparado e a myshell deve esperar pelo seu m antes de exibir outro prompt. • Background: o processo deve ser disparado e a M yShell deve continuar sua execução. Isso pode signicar a continuação da interpretação da linha de co- mandos, se há outros comandos na linha, ou o retorno imediato ao prompt. Cada vez que um processo é disparado em background, M yShell deve ex- ibir uma mensagem a esse respeito, com o identicador (pid) do processo em questão. • Pipe: o conteúdo após o operador deve ser interpretado outro comando a ser executado, sendo que a saída padrão do primeiro processo deve ser conectada 1
  • 5.
    à entrada padrãodo processo seguinte. Para simplicar a implementação, M yShell não permite o encadeamento de pipes, isto é, não é permitido colo- car outro pipe na saída do segundo programa. Pode-se, entretanto, colocar ambos os programas em background terminando a sequência com o operador apropriado (nesse caso, uma mensagem sobre a operação em background deve ser exibida para cada processo). Os comandos internos têm as seguintes interpretações: • CD: muda o diretório corrente da shell. Isso terá impacto sobre os arquivos visíveis sem um caminho completo (path). • PWD: exibe o diretório corrente visto pelo processo. • WAIT: faz com que a shell espere pelo término de todos os processos que possam estare m execução antes de exibir um novo prompt. Cada processo que seja encontrado durante um wait deve ser informado através de uma men- sagem na linha de comando. Caso não haja processos pelos quais esperar, uma mensagem a respeito deve ser exibida e M yShell deve continuar sua execução. • EXIT: termina a operação da shell se não há processos em background. Caso contrário, exibe uma mensagem informando o fato e realiza a operação wait antes de terminar. 2 A implementação da MyShell Mais adiante apresentamos a implementação das funções que trata um comando qualquer que vai ser digitado pelo usuário na M yShell, algumas das funções primi- tivas que serão utilizadas em outras funções estão explicadas abaixo: • Primitiva f ork(): única chamada de sistema que possibilita a criação de um processo em U N IX . • Primitiva execv(): função em que o primeiro argumento corresponde ao cam- inho completo para o executável ou script a ser executado e o segundo é o nome do programa a ser executado. • Primitiva wait(): suspende a execução do processo pai até a morte de seu processo lho (se o lho já estiver morto, a função retorna -1, imediatamente). • Primitiva exit(): ADICIONAR!!!! Algumas bibliotecas da linguagem C que foram utilizadas para a execução do programa: • errno.h • signal.h • sys/types.h • sys/wait.h • unistd.h 2
  • 6.
    2.1 Tratamento da Entrada de dados A função split, representada abaixo, trata a entrada de dados do usuário na M yShell utilizando funções auxiliares da biblioteca string.h denidas na linguagem. 1 char ∗∗ split ( char ∗∗ linha , char ∗∗ vString , char ∗∗ comando , int ∗ tam ) { char ∗ int tok = NULL ; char ∗ sizeof char i ; 5 tok = ( ) malloc ( ( ) ∗200) ; s t r c p y ( tok , ∗ linha ) ; tok = s t r t o k ( tok , n ) ; ∗ comando = s t r t o k ( tok , ) ; 10 // P o s i ç ã o 0 reservada para o execv vString [ 1 ] = s t r t o k (NULL, ) ; if ( ! vString [ 0 ] ) 15 vString [ 0 ] = ; for ( i = 2; vString [ i −1]; i ++){ vString [ i ] = s t r t o k (NULL, ) ; } 20 vString [ i − 1] = NULL ; ∗ tam = ( i − 1) ; return f r e e ( tok ) ; 25 vString ; } Programa 1: Função split 2.2 Função para comando Ls O comando ls, em U N IX , mostra o conteúdo de um diretório passado como argumento. A função abaixo implementada recebe como parâmetro (em forma de string ) os argumentos que foram passados pelo usuário da M yShell: 2 void meu_ls ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / l s ; 5 pid_cd = fork () ; if ( pid_cd == 0) else execv ( / b i n / l s , vArgumentos ) ; 10 int { status1 ; w a i t ( s t a t u s 1 ) ; // e s p e r a a morte de um filho } } Programa 2: Função ls 3
  • 7.
    2.3 Função para comando Pwd O comando pwd, em U N IX , apresenta o diretório corrente do usuário da M yShell. Uma implementação para essa função é apresentada em: 3 void meu_pwd ( char ∗∗ vArgumentos ) { vArgumentos [ 0 ] = / b i n / pwd ; 5 int pid = fork () ; if ( pid == 0) { 10 p r i n t f ( n ) ; e x e c v ( / b i n / pwd , vArgumentos ) ; p r i n t f ( n ) ; else } 15 int { status1 ; w a i t ( s t a t u s 1 ) ; } 20 } Programa 3: Função pwd 2.4 Função para comando Cd O comando cd, em U N IX , abre o diretório passado como argumento pelo usuário da M yShell. Uma implementação para essa função é apresentada em: 4 void meu_cd ( char ∗∗ vArgumentos ) { int pid_cd = 0; 5 if ( pid_cd == 0) char { cwd [ 2 0 4 8 ] ; cwd [ 0 ] = ' 0 ' ; 10 if ( g e t c w d ( cwd , 2048) != NULL) if { ( c h d i r ( vArgumentos [ 1 ] ) != 0) { 15 printf ( It wasn ' t possible set current directory to / n ) ; } } else } 20 int { status1 ; w a i t ( s t a t u s 1 ) ; } 4
  • 8.
    25 } Programa 4: Função cd Para a implementação dessa função utilizamos as funções getcwd() (retorna o nome completo do diretório corrente) e chdir (muda o diretório corrente para aquele passado como parâmetro). 2.5 Função para comando Cat O comando cat, em U N IX , combina um ou mais arquivos e os apresenta na saída padrão, ou seja, mostra o conteúdo de um arquivo passado como argumento pelo usuário da M yShell. Uma implementação para essa função é apresentada em: 5 void meu_cat ( char ∗∗ vArgumentos ) { vArgumentos [ 0 ] = / b i n / c a t ; 5 int pid_cat = fork () ; if ( pid_cat == 0) else execv ( / b i n / c a t , vArgumentos ) ; 10 int { status1 ; w a i t ( s t a t u s 1 ) ; } 15 } Programa 5: Função cat 2.6 Função para comando Grep O comando cat, em U N IX , procura por linhas em arquivos que correspondam a um padrão especicado pelo usuário da M yShell e as apresenta. Uma implemen- tação para essa função é apresentada em: 6 void meu_grep ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / grep ; 5 if pid = fork () ; ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / grep , vArgumentos ) ; 10 p r i n t f ( n ) ; else } int { 15 status1 ; w a i t ( s t a t u s 1 ) ; } 5
  • 9.
    } Programa 6: Função grep 2.7 Função para comando Ping O comando ping , em U N IX , envia pacotes ICM P para um determinado host e mede o tempo de resposta. Uma implementação para essa função é apresentada em: 7 void meu_ping ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / ping ; 5 if pid = fork () ; ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / ping , vArgumentos ) ; 10 p r i n t f ( n ) ; else } int { 15 status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 7: Função ping 2.8 Função para comando Kill O comando kill, em U N IX , envia sinais a determinados processos em execução. Por padrão é enviado o sinal SIGT ERM que requisita a nalização de um processo. Em geral é utilizado na forma 1 , onde pid é o identicador do processo que pode ser obtido através do comando ps 14. Uma implementação para essa função é apresentada em: 8 void meu_kill ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / k i l l ; 5 if pid = fork () ; ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / k i l l , vArgumentos ) ; 10 p r i n t f ( n ) ; else } int { 15 status1 ; 1 kill pid 6
  • 10.
    w a it ( s t a t u s 1 ) ; } } Programa 8: Função kill 2.9 Função para comando Date O comando date, em U N IX , simplesmente exibe a data e a hora atual do sistema no prompt da M yShell. Uma implementação para essa função é apresentada em: 9 void meu_date ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / d a t e ; 5 if pid = fork () ; ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / d a t e , vArgumentos ) ; 10 p r i n t f ( n ) ; else } int { 15 status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 9: Função date 2.10 Função para comando Mkdir O comando mkdir, em U N IX , cria um diretório no diretório atual da M yShell. Uma implementação para essa função é apresentada em: 10 void meu_mkdir ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / mkdir ; 5 if pid = fork () ; ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / mkdir , vArgumentos ) ; 10 p r i n t f ( n ) ; else } int { 15 status1 ; w a i t ( s t a t u s 1 ) ; } } 7
  • 11.
    Programa 10: Funçãomkdir 2.11 Função para comandos Mv, Rm e RmDir Os comandos mv , rm e rmdir, em U N IX , move (ou renomeia) um diretório ou cheiro, remove um determinado cheiro e um remove um diretório, respectivamente. Uma implementação para essa função é apresentada em: 11 void meu_mv( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n /mv ; if pid = fork () ; 5 ( pid == 0) { p r i n t f ( n ) ; e x e c v ( / b i n /mv , vArgumentos ) ; p r i n t f ( n ) ; 10 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } 15 void meu_rm ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n /rm ; if pid = fork () ; 20 ( pid == 0) { p r i n t f ( n ) ; e x e c v ( / b i n /rm , vArgumentos ) ; p r i n t f ( n ) ; 25 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } 30 void meu_rmdir ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / rmdir ; 35 if pid = fork () ; ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / rmdir , vArgumentos ) ; p r i n t f ( n ) ; 40 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } 45 } Programa 11: Funções Rm, Mv e RmDir 8
  • 12.
    2.12 Função para comando Cp O comando cp, em U N IX , permite que o usuário faça cópia de um cheiro para outro, onde o primeiro cheiro (passado como argumento) é lido e copiado para o segundo (no caso da inexistência desse, o mesmo é criado). Uma implementação para essa função é apresentada em: 12 void meu_cp ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / cp ; if pid = fork () ; 5 ( pid == 0) { p r i n t f ( n ) ; e x e c v ( / b i n / cp , vArgumentos ) ; p r i n t f ( n ) ; 10 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 12: Função cp 2.13 Função para comando Chmod O comando chmod, em U N IX , permite que o usuário altere as permissões de um cheiro ou diretório no formato drwxrwxrwx, respectivamente: diretório (d), permissão do dono (read/write/execute), do grupo (read/write/execute) e de outros (read/write/execute). Uma implementação para essa função é apresentada em: 13 void meu_chmod ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / chmod ; if pid = fork () ; 5 ( pid == 0) { p r i n t f ( n ) ; e x e c v ( / b i n / chmod , vArgumentos ) ; p r i n t f ( n ) ; 10 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 13: Função chmod 2.14 Função para comando Ps O comando ps, em U N IX , lista a lista de processos em execução, geralmente utilizado quando se necessita para saber o pid de um processo terminá-lo com o comando kill. Uma implementação para essa função é apresentada em: 14 void meu_ps ( char ∗∗ vArgumentos ) { 9
  • 13.
    int vArgumentos [ 0 ] = / b i n / ps ; if pid = fork () ; 5 ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / ps , vArgumentos ) ; p r i n t f ( n ) ; 10 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 14: Função ps 2.15 Função para comando Sh e Bash Os comandos sh e bash, em U N IX , são interpretadores de comandos feitos para intermediar o usuário e seu sistema. Através deles, o usuário manda um comando, e o interpretador o executa no sistema. Eles são a shelldo sistema. Uma imple- mentação para essa função é apresentada em: 15 void meu_sh ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / sh ; if pid = fork () ; 5 ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / sh , vArgumentos ) ; p r i n t f ( n ) ; 10 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } 15 void meu_bash ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / bash ; if pid = fork () ; 20 ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / bash , vArgumentos ) ; p r i n t f ( n ) ; 25 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 15: Funções Sh e Bash 10
  • 14.
    2.16 Função para comando Sleep O comando sleep, em U N IX , é usado para dar um tempo antes de começar um novo processo pela M yShell. Uma implementação para essa função é apresentada em: 16 void meu_sleep ( char ∗∗ vArgumentos ) { int vArgumentos [ 0 ] = / b i n / s l e e p ; if pid = fork () ; 5 ( pid == 0) { p r i n t f ( n ) ; execv ( / b i n / s l e e p , vArgumentos ) ; p r i n t f ( n ) ; 10 else int } { status1 ; w a i t ( s t a t u s 1 ) ; } } Programa 16: Função sleep 2.17 Função para comando Pipe e Background O comando (pipe), em U N IX , que faz o encadeamento de processosou seja, ele permite que a saída de um comando seja diretamente utilizado em outro comando. Já o comando (background) permite que um processo seja executado em segundo plano, ou seja, a M yShell não cará impedida de inicializar outros processos durante a execução do anterior. Uma implementação para essas funções é apresentada em: 17 int isPipeOrBk ( char ∗ linha ){ int i , tam = strlen ( linha ) − 1; 5 for if ( i =0; i tam ; i ++) return (( linha [ i ] == '| ') || ( linha [ i ] == ' ' ) ) { 1; return } 0; 10 } Programa 17: Função Pipe ( )eBackground() Ao receber o comando do usuário utilizamos a função isP ipeOrBk para vericar em O(n) se o comando contém ou não os caracteres ou . Caso tenha, a função retornará 1 e 0 caso contrário. 2.18 Função para comando Exit O comando exit, em U N IX , termina a execução da M yShell se não há processos em background, caso contrário a ação deverá ser tratada. Uma implementação para essa função é apresentada em: 18 11
  • 15.
    void meu_cat ( char ∗∗ vArgumentos ) { vArgumentos [ 0 ] = / b i n / c a t ; 5 int pid_cat = fork () ; if ( pid_cat == 0) else execv ( / b i n / c a t , vArgumentos ) ; 10 int { status1 ; w a i t ( s t a t u s 1 ) ; } 15 } Programa 18: Função Exit 2.19 Função Principal Abaixo apresentamos a função principal para o funcionamento da M yShell. No corpo da função principal main é feita a entrada dos dados pelo usuário (comandos e argumentos para tais) e o tratamento de cada caso, chamando as respectivas funções que tratam o comando necessitado e ao nal desaloca a memória utilizada na execução do programa. A implementação da função é apresentada abaixo: 19 / ∗ Mini −i n t e r p r e t a d o r ∗/ #include s t d i o . h 5 #include s t d l i b . h #include s t r i n g . h #include u n i s t d . h 10 #include f u n c o e s . h int int char ∗∗ a r g v ) int main ( argc , { linesize = 512; // Tamanho da linha de comando 15 char ∗ char ∗∗ linha = NULL ; // Linha de Comando int vArgumentos = NULL ; // Vetor de argumentos char ∗ tam = 0; // Quantidade de Argumentos int comando = NULL ; // Comando a ser executado 20 i , linhaMatriz = 40 , colunaMatriz = 100; // dimensoes do vetor int de argumentos char ∗ sizeof char ∗ pos ; char ∗ ∗ sizeof char ∗ linha = ( ) malloc ( ( ) 512) ; ∗ linhaMatriz ) ; char ∗ sizeof char vArgumentos = ( ) malloc ( ( ) vArgumentos [ 0 ] = ( ) malloc ( ( ) ∗( linhaMatriz ∗ for colunaMatriz ) ) ; 25 ( i = 1; i linhaMatriz ; i ++) vArgumentos [ i ] = ( v A r g u m e n t o s [ 0 ] [ i ∗ colunaMatriz ] ) ; 12
  • 16.
    p r in t f ( nMYSHELL : ) n ) ; 30 p r i n t f ( DEBUG: PID %d , PPID %d n n , getpid () , getppid () ) ; // pid − Process ID ppid − Parent Process ID while (1) { 35 char cwd [ 2 0 4 8 ] ; // P a s t a atual cwd [ 0 ] = ' 0 ' ; if ( g e t c w d ( cwd , 2048) == NULL) { // 40 p e r r o r ( Nao foi possivel obter o diretorio atual . Padronizando para / n ) ; s t r c p y ( cwd , / ) ; if ( c h d i r ( cwd ) != 0) { 45 p e r r o r ( Nÿo foi possivel acessar o diretorio a t u a l . n ) ; } } 50 newline : p r i n t f ( M y S h e l l :~% s $ , cwd ) ; f g e t s ( linha , linesize , stdin ) ; 55 if n ) == 0 ) goto ( strcmp ( l i n h a , newline ; // s e m p r e que nÿo hý comandos volta para newline if ( isPipeOrBk ( l i n h a ) ) { continue system ( l i n h a ) ; 60 ; } vArgumentos = s p l i t ( l i n h a , vArgumentos , comando , tam ) ; // Guarda os comandos no vetor de args . 65 //A partir desse ponto procura pelo comando digitado e chama a funcao correspondente if ( strcmp ( h e l p , comando ) == 0) { meu_help ( ) ; 70 } else if ( strcmp ( c r e d i t o s , comando ) == 0) { creditos () ; } else if ( strcmp ( l s , comando ) == 0) { meu_ls ( v A r g u m e n t o s ) ; 75 } else if ( strcmp ( e x i t , comando ) == 0) { meu_exit ( 0 ) ; } else if ( s t r c m p ( pwd , comando ) == 0) { 80 meu_pwd ( v A r g u m e n t o s ) ; 13
  • 17.
    } else if ( strcmp ( cd , comando ) == 0) { meu_cd ( v A r g u m e n t o s ) ; 85 } else if ( strcmp ( c a t , comando ) == 0) { meu_cat ( v A r g u m e n t o s ) ; } else if ( strcmp ( w a i t , comando ) == 0) { meu_wait ( ) ; 90 } else if ( s t r c m p ( , comando ) == 0) { meu_background ( ) ; } else if ( strcmp ( p i n g , comando ) == 0) { 95 meu_ping ( v A r g u m e n t o s ) ; } else if ( strcmp ( k i l l , comando ) == 0) { m e u _ k i l l ( vArgumentos ) ; 100 } else if ( strcmp ( d a t e , comando ) == 0) { meu_date ( v A r g u m e n t o s ) ; } else if ( strcmp ( gr ep , comando ) == 0) { meu_grep ( v A r g u m e n t o s ) ; 105 } else if ( strcmp ( mkdir , comando ) == 0) { meu_mkdir ( v A r g u m e n t o s ) ; } else if ( s t r c m p ( mv , comando ) == 0) { 110 meu_mv( v A r g u m e n t o s ) ; } else if ( s t r c m p ( rm , comando ) == 0) { meu_rm ( v A r g u m e n t o s ) ; 115 } else if ( strcmp ( rmdir , comando ) == 0) { meu_rmdir ( v A r g u m e n t o s ) ; } else if ( strcmp ( cp , comando ) == 0) { meu_cp ( v A r g u m e n t o s ) ; 120 } else if ( s t r c m p ( chmod , comando ) == 0) { meu_chmod ( v A r g u m e n t o s ) ; } else if ( strcmp ( echo , comando ) == 0) { 125 meu_echo ( v A r g u m e n t o s ) ; } else if ( strcmp ( hostname , comando ) == 0) { meu_hostname ( v A r g u m e n t o s ) ; 130 } else if ( strcmp ( ps , comando ) == 0) { meu_ps ( v A r g u m e n t o s ) ; } else if ( strcmp ( sh , comando ) == 0) { meu_sh ( v A r g u m e n t o s ) ; 135 } else if ( strcmp ( bash , comando ) == 0) { meu_bash ( v A r g u m e n t o s ) ; 14
  • 18.
    } else if ( s t r c m p ( nano , comando ) == 0) { 140 meu_nano ( v A r g u m e n t o s ) ; } else if ( strcmp ( s l e e p , comando ) == 0) { meu_sleep ( vArgumentos ) ; 145 } else { p r i n t f ( Comando '% s ' nÿo encontrado ! n , comando ) ; } linha [ 0 ] = ' 0 ' ; 150 } f r e e ( vArgumentos [ 0 ] ) ; f r e e ( vArgumentos ) ; } Programa 19: Função Main Aqui é feita a vericação com a função isP ipeOrBk 17 de modo a escolher qual será o uxo de execução do programa de duas maneiras: • Caso a função isP ipeOrBk retorne 1, ou seja, tendo como instrução a execução de um comando em Background ou utilização do Pipe chamamos o comando System do Linux para fazer uma chamada ao Sistema de modo a executar esses comandos. • Caso não haja o programa será executado normalmente de modo que nós é que contralamos a criação dos processos lhos e da execução dos comandos contidos no bin. Note que também estamos utilizando uma matriz para guardar os dados que serão passados pelo usuário da M yShell. Para essa matriz de char(ou seja, vetor de strings) foi feita uma alocação com a quantidade de linhas da matriz de adjacên- cias e mais uma alocação para a posição matriz[0] com tamanho Linha ∗ Coluna, fazendo, em seguida, um redirecionamento dos endereços da matriz. Para melhor entendimento, vide Figura 1 Figura 1: Representação da Alocação de Matriz 15