Ejercicio evaluable de Sistemas Operativos Ingeniería Informática Problema: Aplicar filtros y filtrar salida Escriba un programa en C llamado ’filter’ que acepte una expresión regular como primer argumento, un comando como segundo argumento, y a continuación un número indeterminado de parámetros para la ejecución de dicho comando. El programa tiene que, para cada fichero existente en el directorio actual (omitiendo cualquier directorio presente) imprimir las líneas resultantes de la ejecución del comando cuando ejecuta con dicho fichero como entrada estandar. Las lineas impresas han de ser filtradas, de tal forma que únicamente se impriman las que se ajustan a la expresión regular indicada. PISTA: Se permite ejecutar comandos existentes desde C, pero no se permite ejecutar ni un shell ni scripts. Dos ejemplos de ejecución podrían ser: % ls a b % filter ’lib$’ ls -l -s /sys 0 d-rwxrwxr-x M 19 esoriano esoriano 0 d-rwxrwxr-x M 19 esoriano esoriano % cat a hola caracola % cat b holahola % filter ’^$’ cat % 0 Jan 21 13:57 /sys/lib 0 Jan 21 13:57 /sys/lib -2- Solución #include <u.h> #include <libc.h> void usage(void) { fprint(2, "usage: %s expr cmd args...\n", argv0); exits("usage"); } int togrep(char* expr) { int fd[2]; if(pipe(fd)<0) sysfatal("pipe: %r"); switch(fork()){ case -1: sysfatal("fork"); case 0: close(fd[1]); dup(fd[0], 0); close(fd[0]); execl("/bin/grep", "grep", expr, nil); sysfatal("exec grep: %r"); default: close(fd[0]); return fd[1]; } } -3- void runcmd(int argc, char* argv[], char* in, int outfd) { char* args[512]; // enough char* pname; int fd; int i; if(argc+1 == nelem(args)) sysfatal("fixme. too many args"); for(i = 0; i < argc; i++) args[i] = argv[i]; args[i] = nil; switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)){ case -1: sysfatal("fork: %r"); case 0: fd = open(in, OREAD); if(fd < 0) sysfatal("open %s: %r", in); dup(fd, 0); close(fd); dup(outfd, 1); close(outfd); pname = smprint("/bin/%s", args[0]); exec(pname, args); sysfatal("exec %s: %r", pname); } } -4- void main(int argc, char* argv[]) { int gfd; Dir* d; int nd; int dfd; int i; ARGBEGIN{ default: usage(); }ARGEND; if(argc < 2) usage(); gfd = togrep(argv[0]); argc++; argv++; dfd = open(".", OREAD); if(dfd < 0) sysfatal("open .: %r"); nd = dirreadall(dfd, &d); close(dfd); for(i = 0; i < nd; i++) runcmd(argc, argv, d[i].name, gfd); if(nd > 0) free(d); close(gfd); waitpid(); // can be only grep exits(nil); }