Examen de febrero de 2010

Anuncio
Examen de Sistemas Operativos
Problema: Tardón en C
Implemente un programa llamado tardon que ejecute simultáneamente dos comandos que se indican en
la línea de argumentos (un comando por argumento) de tal forma que en la salida estándar debe salir lo que
el comando que tarde menos en ejecutar escribiese en su salida estándar. Por ejemplo:
; tardon ’sleep 3600’ ’seq 5’
1
2
3
4
5
;
deja como salida la salida de seq dado que ha tardado menos en ejecutar.
Problema: Calcular tamaños
Cree un script llamado dudu.rc que a partir de un directorio, recursivamente, imprima el tamaño de todos
los ficheros en Bytes. Cuando acabe con los ficheros de un directorio, debe imprimir el nombre del directorio y la suma de tamaños para los ficheros que contiene (también en Bytes). Esta suma sólo corresponde a
los ficheros directamente en el directorio (no a todos los ficheros contenidos en el árbol, esto es, en subdirectorios).
El comportamiento es parecido al del comando du(1) del sistema, por lo que no se permite utilizar
este comando.
Para conseguir la lista de ficheros (y su tamaño) de un directorio, se tiene que usar el comando ‘‘ls
-s’’. Nótese que dicho comando indica el tamaño en KBytes y no en Bytes.
-2-
Solución

_______
_dudu.rc
#!/bin/rc
rfork e
if(! ~ $#* 1){
echo usage dudu dir >[1=2]
exit usage
}
total=0
ls -s $1| while(l=‘{read}){
file=‘{echo $l | awk ’{print $2}’};
if(test -d $file)
$0 $file
# call myself for the child dir
if not{
size=‘{echo $l | awk ’{print $1}’};
sizebyte=‘{echo $size^’*1024’ | hoc}
total=‘{echo $total + $sizebyte | hoc}
echo $sizebyte $file
}
}
echo $total $1
exit ’’
Se ha utilizado una construcción
... | while (var=‘{read}) ...
para procesar por separado cada línea en la salida estándar de ls. En general, es mejor evitar esto dado que
de este modo ejecutamos todos los comandos del cuerpo del while cada vez, para cada línea en la entrada.
Dicho esto, en este caso, parecía más directo implementar así el script.
________
tardon.c 

#include <u.h>
#include <libc.h>
static int
startcmd(char *cmd, int fd)
{
int pid, ntok;
char *tok[32];
char *path;
ntok = tokenize(cmd, tok, nelem(tok));
if(ntok == nelem(tok))
sysfatal("%s: command too long\n", argv0);
tok[ntok] = nil;
if(strncmp(tok[0], "/bin/", 5) != 0)
path = smprint("/bin/%s", tok[0]);
else
path = tok[0];
-3-
pid = fork();
switch(pid){
case -1:
return -1;
case 0:
dup(fd, 1);
close(fd);
exec(path, tok);
sysfatal("exec %r");
}
if(path != tok[0])
free(path);
return pid;
}
static void
copyout(int fd)
{
char buf[8*1024];
int nr;
for(;;){
nr = read(fd, buf, sizeof(buf));
if(nr < 0)
fprint(2, "%s: read: %r\n", argv0);
if(nr <= 0)
break;
if(write(1, buf, nr) != nr){
fprint(2, "%s: write: %r\n", argv0);
break;
}
}
}
static void
kill(int pid)
{
char buf[80];
int fd;
seprint(buf, buf+sizeof(buf), "/proc/%d/ctl", pid);
fd = open(buf, OWRITE);
if(fd < 0)
return;
write(fd, "kill", 4);
close(fd);
}
static void
usage(void)
{
fprint(2, "usage: %s cmd1 cmd2\n", argv0);
exits("usage");
}
-4-
void
main(int argc, char *argv[])
{
int pid1, pid2;
int fd1, fd2;
int wpid;
char fname1[80];
char fname2[80];
ARGBEGIN{
default:
usage();
}ARGEND;
if(argc != 2)
usage();
seprint(fname1, fname1+sizeof(fname1), "/tmp/tardon.1.%d", getpid());
fd1 = create(fname1, ORDWR, 0664);
if(fd1 < 0)
sysfatal("create %s: %r", fname1);
seprint(fname2, fname2+sizeof(fname2), "/tmp/tardon.2.%d", getpid());
fd2 = create(fname2, ORDWR, 0664);
if(fd2 < 0)
sysfatal("create %s: %r", fname2);
if(fd2 < 0){
remove(fname1);
sysfatal("create %s: %r", fname2);
}
pid1 = startcmd(argv[0], fd1);
pid2 = startcmd(argv[1], fd2);
wpid = waitpid();
if(wpid == pid1){
kill(pid2);
seek(fd1, 0, 0);
copyout(fd1);
}else{
kill(pid1);
seek(fd2, 0, 0);
copyout(fd2);
}
close(fd1);
close(fd2);
if(remove(fname1) < 0)
fprint(2, "%s: remove %s: %r\n", argv0, fname1);
if(remove(fname2) < 0)
fprint(2, "%s: remove %s: %r\n", argv0, fname2);
exits(nil);
}
Se ejecutan los dos programas en paralelo con la salida redireccionada a un fichero. En cuanto uno contesta,
se mata al otro y se escribe la salida del primero que acabó por pantalla. a continuación se borran los
ficheros temporales que se crearon para recoger la salida de los programas.
Descargar