Neste trabalho você se familiarizará com a interface de chamadas de sistema do Linux implementando algumas funcionalidades num shell simples.
Baixe o esqueleto do shell e o estude. O esqueleto do shell contém duas partes: um processador de linhas de comando e código para execução dos comandos. O processador de linhas só reconhece comandos simples como:
ls > y cat < y | sort | uniq | wc > y1 cat y1 rm y1 ls | sort | uniq | wc rm y
Se você não entende o que esses comandos fazem, estude o manual de um shell do linux (por exemplo, do bash) bem como o manual de cada um dos comandos acima (ls, cat, rm, sort, uniq, wc). Copie e cole esses comandos num arquivo, por exemplo, teste.sh.
Você pode compilar o esqueleto do shell rodando
$ gcc sh.cEsse comando irá produzir um arquivo a.out que você pode rodar:
$ ./a.outPara sair do shell simplificado aperte ctrl+d (fim de arquivo). Teste o shell executando os comandos no arquivo teste.sh:
$ ./a.out < teste.shEssa execução irá falhar pois você ainda não implementou várias funcionalidades do shell. É isso que você fará nesse trabalho.
Implemente comandos simples, como:
$ lsO processador de linhas já constrói uma estrutura execcmd para você, a única coisa que você precisa fazer é escrever o código do case ' ' (espaço) na função runcmd. Depois de escrever o código, teste execução de programas simples como
$ ls $ cat sh.cSe ainda não conhecê-la, dê uma olhada no manual da função exec (digite man 3 exec). Nota: não use a função system para implementar as funções do seu shell.
Implemente comandos com redirecionamento de entrada e saída para que você possa rodar:
echo "6.828 is cool" > x.txt cat < x.txtO processador de linhas já reconhece ">" e "<" e constrói uma estrutura redircmd para você. Seu trabalho é apenas preencher o código na função runcmd para esses casos. Teste sua implementação com os comandos acima e outros comandos similares. Talvez você queira dar uma olhada no manual das funções open e close. Se você não conhece o esquema de entrada e saída padrão de programas, dê uma olhada no artigo da Wikipedia aqui.
Implemente pipes para que você consiga rodar comandos tipo
$ ls | sort | uniq | wcO processador de linhas já reconhece '|' e constrói uma estrutura pipecmd pra você. A única coisa que você precisa fazer é completar o código para o case '|' na função runcmd. Teste sua implementação para o comando acima. Se precisar, leia a documentação das funções pipe, fork e close.
Finalmente, você agora deve conseguir rodar o seguinte comando com sucesso:
$ a.out < t.sh
Não esqueça de responder à pergunta na tarefa 1 presente no esqueleto do shell.
Não use a função system na sua implemencação. Use fork e exec.
Cada um dos extras abaixo valem um ponto extra:
Seu shell será utilizado para executar um script (como em $ ./a.out < teste.sh) e a saída será conferida automaticamente. Por causa disso, seu shell deve imprimir somente a saída dos programas em casos que não ocorrem erro.
Seu código será inspecionado manualmente. Para facilitar o trabalho do professor, seu código será extraído do código do shell usando um script que retira o texto entre os marcadores no texto (MART START e MARK END). Por causa disso, entregue o código em um arquivo único e não retire os marcadores de sua solução final. Verifique se todo o seu código está sendo extraído rodando o script no seu código.