Examen de septiembre de 2009

Anuncio
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);
}
Descargar