Trabalho I: Mini-Shell para UNIX
Objectivo
O objectivo principal deste trabalho é fornecer aos alunos um primeiro
contacto com programação avançada em UNIX tendo como base a linguagem
C. Em particular, pretende-se que os alunos sejam capazes de lidar com
argumentos passados através da linha de comando e com chamadas de
sistema para manipulação de processos, tais como:
fork, pipe, dup2,
exec, wait, exit,
entre outras.
Trabalho
O trabalho é composto por um conjunto de pequenas etapas que no
conjunto levarão à implementação de uma mini-shell para UNIX. A
implementação de cada etapa deve ser o mais robusta possível, i.e., se
uma chamada a uma função do sistema falhar, o programa em execução
deve apresentar uma mensagem de erro apropriada e eventualmente
terminar com um código de exit correcto. Para tal,
procure tirar partido das funções de sistema perror ou
strerror para gerar mensagens de erro
apropriadas. Como exemplo, considere o código que se segue (em que
syscall deve ser substituído pela função a usar):
if (syscall(args) == ERRO) {
perror("syscall");
exit(1);
}
Em nenhuma etapa deve fazer uso das funções de sistema
system ou popen. Como alternativa,
deve recorrer sempre às funções de sistema fork,
dup2 e da família exec.
Etapa 1: Linha de comandos
Use o exercício da primeira aula prática
para implementar o tratamento da linha de comandos da mini-shell.
Etapa 2: Comandos simples
Estenda a mini-shell de forma a executar comandos do
utilizador. Comece por considerar comandos sem argumentos e depois
admita argumentos para os comandos. Assuma que o número máximo de
argumentos para um comando é 100 (#define MAXARGS
100). Exemplos:
- ls
- date
- more nomeficheiro
- ls -l /tmp
- gcc -s -O -g -o pois pois.c
Etapa 3: Redirecionamento de input
Estenda a mini-shell para lidar com redirecionamento simples de
input. A shell deve procurar pelo caracter < e,
caso encontre, deve tratar a palavra que se lhe segue como o nome de
um ficheiro. O input para o comando (parte antes de
<) deve ser lido do ficheiro em vez do standard
input. Se o ficheiro não puder ser lido, deve ser gerado um erro e o
comando não deve ser executado. Exemplos:
- more < ficheiro
- wc < ficheiro
- wc < ficheiro -l
- wc<ficheiro
Etapa 4: Redirecionamento de output
Estenda a mini-shell para lidar com redirecionamento simples de
output. A shell deve procurar pelo caracter > e,
caso encontre, deve tratar a palavra que se lhe segue como o nome de
um ficheiro. O output que o comando (parte antes de
>) gera deve ser enviado para o ficheiro em vez de
para o standard output. Se o ficheiro já existir, deve ser
re-escrito. Se o ficheiro não puder ser criado, deve ser gerado um
erro e o comando não deve ser executado. Exemplos:
- ps -augx > fich1
- ls > ficheiro
- ls > ficheiro -l
- ls>ficheiro
Etapa 5: Encadeamento de comandos
Estenda a mini-shell de forma a suportar o encadeamento de comandos
(uso de pipes). A shell deve procurar pelo caracter |
e, caso encontre, deve tratar as palavras que se lhe seguem como sendo
um segundo comando. O output que o comando inicial (parte antes de
|) gera deve ser enviado para uma pipe em vez de para
o standard output. Por sua vez, o segundo comando (parte depois de
|) deve tomar o seu input a partir da pipe utilizada
pelo primeiro comando para enviar o seu output. Numa segunda fase
estenda a mini-shell de forma a que possa encadear mais do que uma
pipe na linha de comandos. Exemplos:
- ls -l | more
- ps -ef | grep bash | wc
- ls -l|wc -l
Etapa 6: Concorrência
Estenda a sua mini-shell para lidar com concorrência de processos. A
shell deve procurar pelo caracter & e, caso
encontre, deve executar o comando (parte antes do
&) concorrentemente com a própria shell, ou seja,
a shell não deverá esperar que o comando em causa termine para
apresentar a prompt e desse modo aceitar novos comandos. Se o caracter
& não for o último caracter da linha de comandos,
deve ser gerado um erro e o comando não deve ser executado. Exemplos:
- gcc -o pois pois.c &
- emacs &
- emacs&
Etapa 7: Junção final
Caso tenha resolvido separadamente as funcionalidades das etapas
anteriores, junte agora tudo num só programa de forma a que a
mini-shell aceite a combinação dos vários comandos. Se já tiver todo o
desenvolvimento integrado, não tem nada a fazer nesta etapa. Exemplos:
- ls -l /tmp > fich1 &
- grep Ola < fich1 > fich2
- ps -aux | grep root
- grep Ola < fich1 | wc > fich2 &
- ls -l > fich | wc
Prazos
O trabalho deve ser entregue via web até às 12 horas do
dia 11 de Abril de 2008, sendo a sua demonstração feita na aula
prática imediatamente a seguir.
O que entregar? Um ficheiro .tar que inclua:
- Os ficheiros que implementam o conjunto das etapas (pode ser só um);
- A makefile que gera o executável do trabalho (utilizar o nome mini_shell).
O código deve compilar e executar nas máquinas da sala das aulas
práticas. Uma boa estruturação e legibilidade do código será
valorizada.