Examen de Fundamentos de Sistemas Operativos Tiempo total: 2.5 horas. Problema: Llamadas al sistema (7 puntos) Implemente un programa similar a tee(1) que descomprima los datos que lee de la entrada estándar. Una invocación sería como sigue: ; ztee fichsalida < fichentrada El programa debe leer de su entrada estándar datos comprimidos con gzip(1) sin ningún argumento, y debe escribir los datos descomprimidos por su salida estándar. Para descomprimirlos puede ejecutar gunzip(1). Además, el programa debe escribir lo mismo, es decir, el resultado de descomprimir los datos por su salida estándar, en el fichero que recibe como parámetro. Naturalmente, no se permite la utlización del comando tee(1) ni el uso de ficheros temporales. Entrega: Copie un fichero llamado ztee-login.c, donde login es tu nombre de usuario, en el directorio /usr/elf/examen. ATENCIÓN: Sólo se puede efectuar la entrega una vez. Ponga un comentario con su nombre y apellidos en el fichero. -2- Solución ztee.c ______ #include <u.h> #include <libc.h> enum { Blen = 256, }; static void usage(void) { fprint(2, "usage: %s outfile\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { int fd; int p[2]; long len; char buf[Blen]; ARGBEGIN{ default: usage(); }ARGEND if(argc != 1) usage(); if(pipe(p) < 0) sysfatal("pipe: %r"); switch(fork()){ case -1: sysfatal("fork: %r"); case 0: dup(p[1], 1); close(p[1]); close(p[0]); execl("/bin/gunzip", "gunzip", "-v", nil); sysfatal("exec failed"); } fd = create(argv[0], OWRITE, 0664); if(fd < 0) sysfatal("create: %s: %r", argv[0]); close(p[1]); -3- while((len = read(p[0], buf, Blen)) > 0){ if(write(fd, buf, len) != len) sysfatal("%s: write: %r", argv[0]); if(write(1, buf, len) != len) sysfatal("stdout: write: %r"); } if(len < 0) sysfatal("pipe read: %r"); close(p[0]); close(fd); waitpid(); exits(nil); } Problema: Shell Script (3 puntos) Escriba un script de RC llamado listfiles.rc que reciba un número indeterminado de argumentos indicando ‘‘extensiones’’ de ficheros (parte del nombre después del último punto). El programa debe escribir por su salida estándar la lista de todos los ficheros con dicha ‘‘extensión’’ del $home del usuario que tienen permiso de lectura para todos los usuarios, ordenados alfabéticamente y sin elementos duplicados. Por ejemplo, esta podría ser una ejecución del programa: ; listfiles jpg pdf doc /usr/pepe/doc/tesis/figuras/mouse.jpg /usr/pepe/doc/tesis/figuras/sdcard.jpg /usr/pepe/doc/tesis/figuras/tft.jpg /usr/pepe/doc/tesis/figuras/xw9300.jpg /usr/pepe/doc/tesis/portada.pdf /usr/pepe/doc/tesis/presentacion/presentacion.pdf /usr/pepe/doc/var/cartel_puerta.pdf /usr/pepe/doc/www/03.sec-auth.pdf /usr/pepe/doc/www/04.sec-malware.pdf /usr/pepe/tmp/a.doc /usr/pepe/tmp/all.pdf /usr/pepe/tmp/e.pdf Entrega: Copie un fichero llamado listfiles-login.rc, donde login es tu nombre de usuario, en el directorio /usr/elf/examen. ATENCIÓN: Sólo se puede efectuar la entrega una vez. Ponga un comentario con su nombre y apellidos en el fichero. -4- Solución Hay muchas soluciones posibles. Una solución sencilla pero mejorable es la siguiente: __________ listfiles2.rc #!/bin/rc if(~ $#* 0){ echo "usage: listfiles ext ..." >[1=2] exit usage } test -f /tmp/aux && rm /tmp/aux >[2] /dev/null for(i in ‘{du -a $home >[2] /dev/null | awk ’{print $2}’}){ ext=‘{echo $i | sed ’s/.*\.(.*)$/\1/’} if(~ $ext $*){ ls -l $i | grep ’^[^d].......r..’ | awk ’{print $10}’ >> /tmp/aux } } sort -u /tmp/aux >[2] /dev/null rm /tmp/aux >[2] /dev/null exit ’’ El comando du -a no nos da la salida en un orden alfabético ASCII estricto (dado que se recorre el árbol en profundidad, puede desordenar nombres de fichero que comiencen con un símbolo de puntuación). Por esa razón, para cumplir con el enunciado de forma precisa, ordenando y eliminando duplicados (que también se pueden dar en directorios unión, aunque sea un caso raro), ejecutaremos sort sobre un fichero temporal que usamos para almacenar la lista de ficheros que cumplen con los requisitos indicados. Para simplificar, no hacemos que el nombre del fichero temporal sea único para cada ejecución. Esta primera versión es claramente mejorable. En realidad, nos podemos ahorrar el fichero temporal. También podemos prescindir del pipeline usado para conseguir la ‘‘extensión’’ del nombre del fichero, usando el comando ˜ directamente: __________ listfiles3.rc #!/bin/rc if(~ $#* 0){ echo "usage: listfiles ext ..." >[1=2] exit usage } for(i in ‘{du -a $home >[2] /dev/null | awk ’{print $2}’ | sort -u }){ if(~ $i *.$*){ ls -l $i | grep ’^[^d].......r..’ | awk ’{print $10}’ } } exit ’’ Otra solución podría ser la siguiente, en la que componemos una expresión regular a partir de los argumentos para filtrar los ficheros por su ‘‘extensión’’: _________ listfiles.rc #!/bin/rc -5- if(~ $#* 0){ echo "usage: listfiles ext ..." >[1=2] exit usage } regexpr=’\.(’^‘{echo $* | tr ’ ’ ’|’}^’)$’ {for(i in ‘{du -a $home >[2] /dev/null | grep $"regexpr | awk ’{print $2}’ }){ if(ls -l $i | grep -s ’^[^d].......r..’){ echo $i } }} | sort -u