domingo, 23 de diciembre de 2007

CVS a lo cutre

Acabo de inaugurar esta parte de mi blog para que veáis hasta que punto una persona puede volverse loco en una tarde.
El objetivo de este apartado es observar los cambios realizados en el sistema operativo MINIX 3 sin tener porque saber que ficheros hemos tocado. Para poder desarrollarlo me he tenido que devanar los sesos y recordar aquellas maravillosas clase de UNIX en primero de carrera.

Descargar Link: cambios_shx.pdf

1. Lo primero que he hecho ha sido bajarme una imagen nueva de la página de la asignatura.
2. Una vez que tenemos la imagen nueva, vamos a hacer una copia del directorio “/usr/src” y subdirectorios, pero necesitamos saber a dónde.
3. Para ver cómo está distribuido el sistema de ficheros utilizamos el commando:
#df

1.jpg

Observamos que en “/usr” hay un 99% de ocupación por lo que no nos vale, necesitamos por ejemplo utilizar “/home” para nuestro fin, ya que su índice de ocupación es del 11%.
4. Una vez que sabemos en donde vamos a realizar la copia, procedemos a ello:

#cp -r /usr/src /home

5. Con esta sencilla operación obtenemos en el directorio “/home” un subdirectorio “/home/src” en donde está todo el código fuente de MINIX 3.0.
6. Ahora viene la tediosa tarea de hacer la práctica 0, 1, 2 ó 3 (esta parte os la dejo a vosotros).
7. Una vez que hemos realizado la práctica correspondiente tenemos que ir al punto 8.
8. NOS LLEVAMOS LAS MANOS A LA CABEZA PORQUE NO SABEMOS COMO VER TODOS LOS CAMBIOS QUE HEMOS REALIZADO NI QUEREMOS RECORRERNOS TODO EL SISTEMA DE FICHEROS, PUES TRANQUILOS LA SOLUCIÓN ESTÁ EN EL PUNTO 9.
9. Como hemos realizado una copia de cada fichero en “/usr/src” en “/home” antes de haberlos modificado solo tenemos que comparar los 4343 ficheros que tiene “/usr/src” de uno a uno.
Este cálculo ha sido aproximado y realizado de la siguiente forma:

#find . | wc –l

10. Como eso es una tarea muy muy tediosa me he currado un script que hace lo siguiente.
11. Antes de nada indicar que mis conocimientos de UNIX y sus maravillosos comandos, es muy reducido, seguro que existe una forma más sencilla de hacerlo o con menos pasos, así que acepto sugerencias que no soy perfecto. Lo que hace básicamente este script es:
a. Borra la pantalla (para empezar no está mal ehhhh)

clear

b. Utilizo 2 ficheros temporales cada vez que se inicia el script comprueba si existen y si existen se borran.

if test -f fich_1.txt ; then
rm fich_1.txt ;
fi
if test -f fich_2.txt ; then
rm fich_2.txt ;
fi


c. Busco en el directorio actual, (por lo que me posiciono en “/usr/src”), todos los ficheros que sean FICHEROS y que no sean código objeto, la lista de ficheros resultantes se inserta en el fichero “fich_1.txt”.

find . \( ! -name '*.o' -a -type f \) > fich_1.txt ;

d. El contenido del fichero “fich_1.txt” es del tipo reseñado a continuación por lo que aplico el siguiente filtro.

./directorio/directorio/ficheroA
./directorio/directorio/ficheroB
./directorio/directorio/ficheroC
./directorio/directorio/ficheroD
./directorio/directorio/ficheroE


e. Extraigo de cada línea de “fich_1.txt” el “./” y lo sustituyo por “NADA”. Utilizo para ello el comando “sed”, donde busca con una expresión regular el comienzo de línea con “./” y lo cambia por “NADA”. El resultado lo envía a “fich_2.txt”.

sed 's/^\.//g' fich_1.txt > fich_2.txt ;

f. El contenido del fichero “fich_2.txt” es del tipo reseñado a continuación por lo que aplico el siguiente filtro.

directorio/directorio/ficheroA
directorio/directorio/ficheroA
directorio/directorio/ficheroA
directorio/directorio/ficheroA
directorio/directorio/ficheroA


g. A continuación utilizo “awk” ya que este comando trata cada “aparición” de texto en una línea como un campo por lo que voy a poder tratar cada línea como un campo.

awk -f rules.awk fich_2.txt > fich_1.txt

h. El comando anterior aplica el fichero de reglas para “rules.awk” a “fich_2.txt” y el resultado lo envía a “fich_1.txt”. El comando “awk” funciona de forma que se puede aplicar un filtro al inicio, otro a cada campo de cada línea y otro al final, en mi caso solo me interesa aplicar un filtro a cada campo de cada línea, pero como en cada línea solo hay un campo, sólo se hará una vez por línea. El contenido de “rules.awk” es el siguiente:

{
print "if test -f /home/src" $1 " ; then ";
print " diff /home/src" $1 " /usr/src" $1 " > /res/" ar[split($1,ar,"/")] ".diff ;" ;
print " echo -n + ;";
print "fi" ;
}


i. Las reglas para “awk” hacen los siguiente para cada línea, primero tenemos en cuenta que la línea 1 va a ser el campo 1, que se representa por $1. Lo que aquí estamos haciendo es simplemente escribir un texto NO ESTAMOS EJECUTANDO NADA. El campo $1 contiene una serie de directorio y termina en un fichero. Comprobamos si el fichero de la línea i-ésima existe, si es así escribe la sentencia:

“diff /home/src/[contenido_de_$1] /usr/src/[contenido_de_$1] > [fichero_de_$1].diff”

j. Después de escribir la línea anterior escribe un “echo” y finaliza el “if”.
k. Resultado:

If test -f /home/src/dir1/dir2/fich1 ; then
diff /home/src/dir1/dir2/fich1 /usr/src/dir1/dir2/fich1 > /res/fich1.diff ;
echo -n + ;
fi


l. Una vez que tenemos esta sentencia por cada línea del fichero, se envía todo esto a un nuevo fichero temporal.
m. Ejecutamos con “sh” ese fichero temporal, el resultado será que si existe el fichero hace la comparación y guarda el resultado en el directorio “/res” añadiéndole la extensión “.diff”. Confío en que no se modifique en 2 sitios diferentes 2 ficheros que tengan el mismo nombre y modificaciones diferentes.
n. Si todo va bien crea el directorio de resultados y ejecuta con “sh”.

if test ! -d /res ; then
mkdir /res ;
cd /res ;
fi
echo "Aplicando filtro [diff]..." ;
sh fich_1.txt


o. Como al hacer diff se puede crear ficheros de tamaño 0, con la siguiente sentencia los elimino.

find /res -size 0 -exec rm {} \;

p. Por último muestro con “ls” el total de ficheros que han cambiado.

ls -l /res


q. El resultado es lo que se muestra a continuación.

2.jpg
3.jpg

Fichero .awk: (solo he podido subirlo en PDF): rulesawk.pdf
Fichero .sh: (solo he podido subirlo en PDF): cambiossh.pdf

Espero que esto os sirva de ayuda o no, quien sabe.

Salu2

domingo, 9 de diciembre de 2007

Práctica 3 - SO II (práctica 2 opción 2)

Buenas tardes, empiezamos esta didáctica guía sobre los estresijos de la práctica 3 de SOII. Este es el resultado que yo he conseguido, como veis hay cosas que no se pedían pero así queda mas bonito. Esta imagen está recortada para que "quepa" en el blog.

Se muestra el número de proceso, el nombre y el número de mensajes enviados.

31.jpg

Imagen en grande: LINK.

Cualidades:
1.- Muestra solo los procesos QUE EXISTEN ACUALMENTE.
2.- Muestra el nombre de los procesos para no estar constantemente pulsando F1 o F3.
3.- Cada vez que se crea un proceso BORRA su contador.
4.- Actualiza el contador no solo al enviar un menaje sino tambien al RECIBIR. (Acordaros de que estamos en rendevouz).

En mi caso yo he realizado una copia del CODIGO FUENTE para mostraros más tarde una cosilla interesante.

Todo el texto que está antes del punto 5.1 es conveniente leerlo para saber de que estamos hablando pero aún asi y todo comenzamos:

5.1 Lo primero que vamos a hacer es proporcionar una funcionalidad sencilla a una tecla de función (F8) que originalmente no tenía ninguna acción asociada. Las teclas de función están definidas bajo el servidor IS en el directorio /usr/src/servers/is. El fichero a modificar para ello se llama dmp.c. Una prueba sencilla de definición de la tecla de función puede ser utilizar la tecla F8 para duplicar la funcionalidad de una ya definida (por ejemplo, F9). Es importante también incrementar la constante que representa el número de enganches definidos (NHOOKS) en el mismo fichero, ya que dicha constante refleja el tamaño del array hooks de teclas de función. Cuando hayamos realizado estos cambios en el fichero dmp.c, recompilaremos el sistema y probaremos su nuevo funcionamiento.


21.jpg

Una vez que modificamos NHOOKS y que duplicamos para la tecla F8 continuamos.

5.2 En este paso vamos a definir las variables y código necesario para contar dentro del kernel el número de mensajes que ha enviado un proceso. Para contar el número de mensajes, una posible solución sería añadir un nuevo campo a los descriptores de la Tabla de procesos, llamado por ejemplo messg_sn. El problema es que estaríamos modificando una estructura muy delicada del kernel de MINIX, de la que también depende el código ensamblador. Por ello, a continuación recomendamos un solución alternativa.


5.2.1 Vamos a definir un array messg_sn con el mismo número de elementos que la tabla de procesos. Este array contendrá el contador de mensajes enviados por cada proceso, de tipo long. La declaración de este array se realizará en el fichero /usr/src/kernel/proc.h como sigue:


EXTERN long messg_sn[NR_TASKS+NR_PROCS];



Además, bastará con pasar una copia íntegra de este array al IS cuando éste lo solicite para efectuar el volcado por pantalla.


Nos quedaremos con éste párrafo ya que será importante para el final de la práctica.


5.2.2 A continuación debemos dar el valor inicial 0 a todos los elementos del array de “mensajes enviados” en el fichero /usr/src/kernel/main.c.


Para esto no hace falta que os diga nada, ya sabeis como poner un array a 0. Solo teneis que tener en cuanta que aquí se debe de inicializar TODO el array.


5.3 En el apartado anterior se han inicializado los contadores de mensajes de los procesos. Ahora vamos a introducir la actualización de dichos contadores de acuerdo con los mensajes enviados en el fichero /usr/src/kernel/proc.c.


En este apartado vamos a tener en cuenta el siguiente gráfico.

111.jpg
211.jpg
311.jpg

5.3.1 El contador de mensajes enviados por un proceso debe incrementarse cada vez que se llame al procedimiento mini_send. Si quisiéramos hacer un control más exacto de los mensajes enviados, deberíamos tener en cuenta cuáles son realmente recibidos pero, por simplicidad, vamos a mantener la solución indicada.


Mas o menos lo que intento decir es que si un proceso NO ESTÁ ESPERANDO un mensaje, el emisor se bloquea y al revés, si no está esperando recibirlo se bloquea el emisor hasta que el receptor quiera.

En la práctica solo se pide que contabilizar cuando un proceso envía, pero tambien sería conveniente aunque no es estrictamente lo que se pide, contabilizar cuando un proceso recibe, la explicación es la siguiente:

Si un proceso A intenta enviar un mensaje un proceso B y éste último no está esperando recibirlo, el proceso A se bloquea. En el supuesto solicitado en la práctica este mensaje enviado se pierde (su cuenta) ya que, el receptor recibe el mensaje cuando hace un mini_receive. Digamos que la práctica solo pide que se contabilice cuando un mensaje es enviado directamente de a un receptor que está esperando recibirlo.

5.3.2 Lo siguiente que nos interesa es posibilitar que el núcleo proporcione al IS información sobre los contadores de mensajes enviados, para que éste pueda proporcionársela, a su vez, a los procesos de usuario. El núcleo proporciona una llamada al sistema sys_getinfo para poder extraer distintas informaciones internas del mismo. Esta llamada se implementa en /usr/src/kernel/system/do_getinfo.c, a través de una sentencia case (switch en C) que extrae la información especificada. Vamos
a definir una nueva etiqueta GET_MESSGSN para indicar en la sentencia case que queremos obtener información sobre los
contadores de mensajes enviados por los procesos. En do_getinfo.c vamos a añadir un nuevo caso etiquetado con la constante GET_MESSGSN. Para dar valor a esta constante, debemos tener en cuenta cuál es el siguiente valor disponible una vez
definidas todas las anteriores etiquetas de la sentencia case. El esqueleto de la sentencia a incluir sería:

case GET_MESSGSN: {
length = ......;
src_phys = vir2phys(......);
break;
}


donde debemos indicar en length la longitud de nuestro array de contadores y como parámetro de vir2phys la dirección física de
messg_sn para que luego se envíe con phys_copy.


En este caso no hace falta comentar mucho, los puntos suspensivos son para decir que en LENGTH se debe poner la longitud del array, si no somos muy listos vamos un par de páginas antes y vemos ejemplos de como se hace y veremos lo siguiente:

a.jpg

Ehhhh que nuestro array no es un STRUCT, no vaya a ser que alguno pongo lo que no es.

En el siguiente apartado tenemos que poner la dirección física y todos sabemos que la dirección física de algo en C se obtiene con:


a1.jpg

5.3.3 Al tratarse de una constante que debe importarse desde el kernel y desde el IS, la constante GET_MESSGSN debe definirse en el fichero /usr/src/include/minix/com.h, y su valor debe ser diferente al de otras etiquetas ya definidas.


Aquí puede pasarte que en vez de poner:

#define GET_MESSGSN .........

pongas

#define GET_MESSGSN 16

y que MINIX al compilar te de un error de identificador por duplicado, PUES NO TE PREOCUPES, me pasó a mi y a un montón de gente, incluso algún profesor seguro que también ha picado. Cuando te dice que el valor debe ser diferente pones uno más al que existe como último, en este caso el último es 16, pues tu sabrás cual es el siguiente.


5.3.4 El fichero /usr/src/include/minix/syslib.h contiene prototipos para permitir que algunos componentes del sistema operativo puedan acceder a los servicios de otros componentes. Por cuestiones estéticas y por seguir el método utilizado por los desarrolladores de MINIX, recomendamos definir en dicho fichero la siguiente macro:

#define sys_getmessgsn(dst) sys_getinfo(GET_MESSGSN,dst,0,0,0)



Esta es una de las líneas más interesantes de la práctica y ya sabrás al final porque, ahora acuerdate que unas lineas arriba dije que recordaras un párrafo, pues este el segundo párrafo que debes recordar.



5.4 Para poder probar que el código introducido es correcto, vamos a conectar la tecla de función que definimos en el paso 1
con la impresión de los contadores de mensajes enviados. Para ello, vamos a empezar por definir una función que nos permita
imprimir los contadores de mensajes enviados.

5.4.1 Tomando como modelo las funciones xxxxdmp del fichero /usr/src/servers/is/dmp_kernel.c, vamos a definir una función
messgsn_dmp que traiga los contadores del kernel y los imprima.


Pues eso te vas al fichero dmp_kernel.c y te creas una función que por ejemplo su ÚNICO codigo para probar sea:

printf("\nMI PRIMER PROGRAMA EN C");

jejejejej

El resultado saldrá cuando COMPILES, REINCIES CON LA OPCIÓN 3 Y PULSES F8.

5.4.2 Para poder definir la función messgsn_dmp en un fichero y asociarla a una tecla en otro, es necesario definir un prototipo
para la misma en /usr/src/servers/is/proto.h.


Pues más de lo mismo, te vas al fichero proto.h y haces un COPY & PASTE de alguna función similar.

5.4.3 Ahora sólo nos queda enganchar la tecla F8 en el fichero /usr/src/servers/is/dmp.c a la nueva función messgsn_dmp.


Esta es la parte más delicada, si no haces esto todo lo que has leído no sirve para nada. Lo que tienes que hacer es decirle a la tecla F8 que ahora su función ya no es la que definistes en el punto 5.1 sino la que tu has creado en el punto 5.4.1

5.4.4 Vamos a compilar en este punto para comprobar si podemos mostrar el array de contadores en su estado actual. Tras
compilar, ejecutaremos los comandos:

halt
boot


Esta parte no necesita explicación.

Una vez dentro de MINIX, teclearemos F8 y veremos si los contadores se han actualizado de forma razonable.


Mi aportación personal es:

1.- Que a la hora de hacer fork se borre el contador de ese proceso.
2.- Mostrar el nombre del proceso i-ésimo.
3.- Mostar solo los proceso NO MUERTOS, es decir VIVOS.

Ahora vienen los párrafos que os decía que recordárais:

1.- El primero es muy importante ya que sin esta pequeña aclaración NO COMPILA. El erro que da es el siguiente:

a2.jpg

Para solucionarlo tienes 2 opciones:

A) Hacer la variable MESSG_SN global en GLO.H (esta opción no la he probado).
B) Hacer la variable MESSG_SN pública en DMP_KERNEL.C (esto es lo que yo hice).

2.- Lo segundo que teneis que tener en cuenta es que por mucho que hagamos público el array hay que llenarlo de datos. Mas concretamente os digo que para hacer que el array tenga datos, hay que llamar a la función SYS_GETMESSGSN, esta macro llamará a SYS_GETINFO y con eso obtenemos en MESSG_SN el array deseado.

Esto es todo, espero haber sido claro al 99,9% tampoco quiero serlo al 100% ya que me llevaría a malo entendidos.

Resultado:

a4.jpg
a3.jpg
a33.jpg
a22.jpg
Archivo completo: LINK.

Salu2.

lunes, 3 de diciembre de 2007