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.