Examen de Sistemas Operativos 3er Curso, Ingeniería Informática Septiembre 2009 Problema: Find Crea un programa (en C o en Rc) llamado find que recorra recursivamente un árbol de ficheros buscando ficheros y ejecutando en ellos las acciones indicadas por sus argumentos. Si no se indica argumento alguno entonces el programa debe tan sólo imprimir el nombre de cada fichero. -n nombre Con esta opción, find debe sólo ejecutar su acción sobre aquellos ficheros cuyo nombre sea nombre. Si esta opción no está presente entonces find realiza su acción sobre todos los ficheros en el árbol. -x Con esta opción, find debe sólo ejecutar su acción sólo sobre ficheros que tengan permiso de ejecución para el propietario. -c cmd ... Con esta opción, find debe ejecutar el comando cmd ... fichero para cada fichero considerado (ver las opciones anteriores). Hay que tener en cuenta que cmd puede ser una única palabra o varias. Dado que la opción -c es la última en la línea de comandos, se entiende que todos los argumentos (desde cmd en adelante) son los que corresponden a la línea de comandos que se desea ejecutar para el fichero. Si el comando cmd tiene errores entonces find debe dejar de recorrer el árbol de ficheros inmediatamente. Sin esta opción find debe tan sólo escribir el nombre de cada fichero. Por ejemplo, ; find $home -n NOTAS debe imprimir el nombre de todos los ficheros llamados NOTAS en nuestro $home. Un ejemplo sería: ; find $home -n NOTAS /usr/elf/doc/NOTAS /usr/elf/doc/courses/so/NOTAS Otro ejemplo: ; find $home/bin -x -c ls -l debe ejecutar ls -l sobre cada fichero con permiso de ejecución en nuestro $home/bin. Por ejemplo: ; find $home/bin --rwxrwxr-x M 13 --rwxrwxr-x M 13 --rwxrwxr-x M 13 --rwxrwxr-x M 13 -x -c ls -l elf sys 201 elf sys 435 elf sys 607 elf sys 317 Jun Oct Jun Jun 21 17 21 21 2007 2005 2007 2007 /usr/elf/bin/rc/users /usr/elf/bin/rc/usersvnc /usr/elf/bin/rc/vacchain /usr/elf/bin/rc/varenas -2- Solución La solución mostrada aquí es algo más compleja de lo que se pedía realmente. No obstante, esta solución funciona mejor que la más simple que encaja con el enunciado. _____ _find.c #include <u.h> #include <libc.h> static void usage(void) { fprint(2, "usage: %s file [-x] [-n name] [-c cmd ...]\n", argv0); exits("usage"); } static void find(char *file, Dir *d, int xflag, char *name, int nargs, char **args); static void finddir(char *file, int xflag, char *name, int nargs, char **args) { int fd; Dir *dirs; int ndirs; int i; char *nfile; fd = open(file, OREAD); if(fd < 0) sysfatal("%s: %r", file); ndirs = dirreadall(fd, &dirs); close(fd); for(i = 0; i < ndirs; i++){ nfile = smprint("%s/%s", file, dirs[i].name); find(nfile, &dirs[i], xflag, name, nargs, args); free(nfile); } free(dirs); } static void runcmd(char **args) { char *bin; Waitmsg *m; -3- switch(fork()){ case -1: sysfatal("fork: %r"); case 0: bin = smprint("/bin/%s", args[0]); exec(bin, args); sysfatal("exec: %r"); default: m = wait(); if(m->msg[0]) sysfatal("%s: %s", args[0], m->msg); free(m); } } static void find(char *file, Dir *d, int xflag, char *name, int nargs, char **args) { int fileok; fileok = 1; if(xflag != 0) if((d->qid.type&QTDIR) != 0 || (d->mode & 0100) == 0) fileok = 0; if(fileok && name != nil) if(strcmp(d->name, name) != 0) fileok = 0; if(fileok) if(args == nil) print("%s\n", file); else{ args[nargs] = file; runcmd(args); } if(d->qid.type&QTDIR) finddir(file, xflag, name, nargs, args); } static char** mkargs(int argc, char **args) { char **nargs; int i; /* args, file, nil */ nargs = malloc((argc+1+1)*sizeof(char*)); if (nargs == nil) sysfatal("no memory"); for(i = 0; i < argc; i++) nargs[i] = args[i]; nargs[argc] = nil; /* file arg */ nargs[argc+1] = nil; return nargs; } -4- void main(int argc, char *argv[]) { char *file; int xflag; char *name; int cflag; Dir *d; char **execargs; argv0 = argv[0]; cflag = xflag = 0; name = nil; execargs = nil; if(argc < 2) usage(); file = argv[1]; argv[1] = argv[0]; argc--; argv++; /* file arg is before any option */ ARGBEGIN{ case ’x’: xflag = 1; break; case ’n’: name = EARGF(usage()); break; case ’c’: cflag = 1; break; default: usage(); }ARGEND; if(cflag == 0 && argc != 0) usage(); if(cflag != 0 && argc == 0) usage(); d = dirstat(file); if(d == nil) sysfatal("%s: %r", file); if(cflag) execargs = mkargs(argc, argv); find(file, d, xflag, name, argc, execargs); free(execargs); free(d); exits(nil); }