PRÁCTICAS DE LABORATORIO DE SISTEMAS OPERATIVOS

PRIMERA SESIÓN


  1. Configuración del entorno de trabajo.

    Si no se configura bien el entorno de trabajo, se rendirá mucho menos en la realización de las prácticas. Primero hay que configurar el terminal. Para ello, hay que poner de acuerdo al programa de terminal que tenéis instalado en el aula de informática con la configuración que tiene el servidor donde se realizarán las prácticas.
    Antiguamente los servidores eran accedidos mediante un dispositivo denominado terminal. Fundamentalmente constaban de un monitor y un teclado y la suficiente electrónica para recoger los caracteres tecleados y mostrar otros por la pantalla. Los caracteres recogidos se enviaban a través de una línea de conexión (normalmente serie) hasta el servidor y, la respuesta de este llegaba al terminal por la misma línea.
    Actualmente, el esquema es diferente. En lugar de un terminal se dispone de PCs de propósito general y un programa que emula el comportamiento de los antiguos terminales. La conexión en lugar de hacerse a través de una línea dedicada, se realiza por Internet y siguiendo un protocolo, que normalmente para conexiones de texto será TELNET. Es preferible, no obstante, usar protocolos cifrados de comunicación, como SSH.

    Programas para PC emuladores de los distintos modelos de terminales existen muchos. Debéis usar aquel que más os guste y que mejor sepáis configurar. Aquí os doy tres ejemplos que os pueden servir de guía para configurar cualquier otro programa, aunque os recomiendo que uséis el primero, pues usa SSH en lugar de TELNET.
    1. PuTTY (SSH) [Recomendado]
    2. Programa TELNET por defecto de Windows NT 4.x y sucesivos
    3. Wyse Term (Aula de informática 5)

    ¡Atención! No se atenderán dudas relativas a la presentación, falta de caracteres en español, descolocación de las pantallas del editor de quienes utilicen programas emuladores distintos o no los configuren del modo antedicho. Trabajar con una mala configuración entorpece la programación.

     Si usáis linux, no necesitáis ningún programa externo. Os basta con abrir un terminal y poner:
                ssh -l vuestro_login_de_encina encina.fis.usal.es
    La huella digital que os debe poner la primera vez que os conectéis es:
    4D:FE:15:17:09:18:41:30:2E:0A:E4:38:73:42:45:29
    Verificar esta huella sirve para evitar ataques al protocolo de seguridad encriptado ssh.

    Encina usa la codificación iso8859-1 para tratar con los caracteres propios del español (ñ, acentos, aperturas de interrogación y exclamación, etc.). Vuestro Linux, sin embargo, usa UTF-8, que es mejor. Para que podáis ver bien estos caracteres en el terminal de Linux, cambiad la codificación en el menú de "Preferencias", "Codificación", "Europeo occidental (iso8859-1)"

    Para poder realizar un FTP y subir o bajar ficheros al servidor, debéis usar la versión segura del protocolo: sftp. En el caso de Windows, se puede usar PSFTP, dentro del directorio de PuTTY. Si hablamos de Linux, la orden que hay que usar es:
                sftp vuestro_login_de_encina@encina.fis.usal.es


  2. Conexión con el servidor.

    El servidor que usaremos para hacer las prácticas se llama en Internet encina.usal.es. En el programa emulador que uséis debéis indicar el nombre del servidor para conectaros. Teclead encina.usal.es. Si no lograrais conexión, probad con la dirección IP de encina, pues puede que no funcione el servidor de nombres de la universidad. Teclead en ese caso: 212.128.144.28.
    Os tiene que aparecer una pantalla parecida a esta:
    
    
    
                    ######  #    #   ####      #    #    #    ##
                    #       ##   #  #    #     #    ##   #   #  #
                    #####   # #  #  #          #    # #  #  #    #
                    #       #  # #  #          #    #  # #  ######
                    #       #   ##  #    #     #    #   ##  #    #
                    ######  #    #   ####      #    #    #  #    #
    
                     ########  UNIVERSIDAD DE SALAMANCA ########
                       Departamento de Informática y Automática
                                 Facultad de Ciencias
    
     "Este ordenador sólo puede ser utilizado por personas debidamente autorizadas"
    
    
    login:
    
                
    Teclead ahora vuestro login y contraseña.

    En el caso de que estéis usando el programa TELNET de Windows NT 4.x, aumentad el tamaño de la ventana de modo que no queden barras de desplazamiento ni horizontales ni verticales en la ventana del terminal.


  3. Configuración de vuestra cuenta en encina.

    Para que la conexión con encina funcione correctamente, es necesario configurar bien vuestra cuenta.
    Editad el fichero .profile situado en el directorio de conexión. Dicho fichero es de tipo "script" y se ejecutará cada vez que os conectéis al servidor. De las instrucciones que aparecen a continuación, aquellas que sean nuevas las debéis añadir en un lugar donde se vayan a ejecutar (no las pongáis dentro de un if, por ejemplo). Aquellas que ya existan, debéis modificarlas adecuadamente (puede ser que alguna de ellas ya estén correctamente en vuestra cuenta). Tened cuidado porque sólo tenéis que copiar lo que aparece señalado en azul, no los signos de puntuación que aparecen a continuación:
    Probad si os funciona la tecla de borrado. Si no es así, volved a editar el fichero .profile. Añadid una línea que diga: stty erase <CTRL+V><TECLA_DE_RETROCESO>. Debéis pulsar primero las teclas "Control" y "V" y, a continuación, pulsar la tecla de retroceso.

    Comprobad que las modificaciones que habéis hecho funcionan desconectándoos y volviéndoos a conectar para que se ejecute el fichero .profile. También podéis, alternativamente, teclear exec login.


  4. Primera prueba.

    Vamos a compilar un programa como si fuera una de las prácticas que tenéis que realizar:

    Ya tenemos los ficheros fuente que componen el programa. Ahora es el momento de crear los ejecutables. Para ello, debéis crear lo que se denomina un makefile. Un makefile es un fichero que le dará al ordenador una serie de reglas acerca de los pasos que ha de ejecutar para llegar a producir el ejecutable. Para recordar lo que vimos en teoría acerca de los makefiles, pulsa aquí.
    Recordemos también los pasos que hay que dar para llegar al ejecutable:



    El orden en que se escriben las reglas en un fichero makefile no importa, salvo la primera, que ha de ser la más general. Si observamos el dibujo, la primera regla debe decir algo así como: "Para obtener el fichero ejecutable prueba, necesito los ficheros objeto prueba.o y raiz.o y lo obtengo mediante la orden c89 prueba.o raiz.o -o prueba -lm". Esta regla, traducida al lenguaje del fichero makefile quedaría así:
    prueba: prueba.o raiz.o
    <TAB>c89 prueba.o raiz.o -o prueba -lm

    Observad cómo se añade -lm a la orden de enlazado porque el código de la función sqrt no se encuentra en raiz.o, sino en la biblioteca del sistema libm.a. El código de la mayor parte de funciones del C estándar se encuentra también en otra biblioteca de funciones, la libc.a pero, como excepción, no hay que indicarle al enlazador que use esa biblioteca, lo hace automáticamente.
    El fichero makefile completo queda así:
    prueba: prueba.o raiz.o
    <TAB>c89 prueba.o raiz.o -o prueba -lm

    prueba.o: prueba.c raiz.h
    <TAB>c89 -c prueba.c

    raiz.o: raiz.c
    <TAB>c89 -c raiz.c

    Tenemos, pues, cuatro ficheros en el directorio PRUEBA. Podemos decirle al ordenador que compile el programa:
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ ls -l
    total 8
    -rw-r--r--   1 gyermo     profes         156 Feb 16 12:01 makefile
    -rw-r--r--   1 gyermo     profes         316 Feb 16 11:17 prueba.c
    -rw-r--r--   1 gyermo     profes         110 Feb 16 11:18 raiz.c
    -rw-r--r--   1 gyermo     profes          29 Feb 16 11:18 raiz.h
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ make
            c89 -c prueba.c
            c89 -c raiz.c
            c89 prueba.o raiz.o -o prueba -lm
                
    Vemos que tenemos los ficheros objeto (.o) y el ejecutable, que ya podemos ejecutar:
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ ls -l
    total 132
    -rw-r--r--   1 gyermo     profes         135 Feb 16 12:29 makefile
    -rwxr-xr-x   1 gyermo     profes       61440 Feb 16 12:37 prueba
    -rw-r--r--   1 gyermo     profes         314 Feb 16 12:32 prueba.c
    -rw-r--r--   1 gyermo     profes         988 Feb 16 12:37 prueba.o
    -rw-r--r--   1 gyermo     profes          77 Feb 16 12:37 raiz.c
    -rw-r--r--   1 gyermo     profes          29 Feb 16 12:37 raiz.h
    -rw-r--r--   1 gyermo     profes         764 Feb 16 12:37 raiz.o
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ prueba
    La raíz cuadrada de 2 es 1.414214.
                
    Lo bueno de los ficheros makefile es que si realizáis alguna modificación, el ordenador sólo realizará las compilaciones necesarias. Probad a cambiar el fichero prueba.c para que calcule la raíz cuadrada de 3 y haced a continuación un make.

    Puede que, en alguna circunstancia, deseéis que make recompile todo de nuevo. En ese caso, teclead touch *.c *.h. Esta orden actualiza la fecha de modificación de todos los ficheros con extensiones .c o .h para que make crea que los acabamos justo de editar.

    NOTA: Si no os funciona touch, probad con tocar.

  5. Argumentos y códigos de retorno de los programas.

    Los programas que se lanzan en la shell pueden llevar argumentos y devolver valores al sistema operativo. En el caso de la orden:
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ ls -l
    total 132
    -rw-r--r--   1 gyermo     profes         135 Feb 16 12:29 makefile
    -rwxr-xr-x   1 gyermo     profes       61440 Feb 16 12:37 prueba
    [...]       
    diremos que el fichero ejecutable /bin/ls se ha ejecutado con un argumento (-l). Diremos que -l es el argumento número 1 de esa ejecución. Abusando del lenguaje, el propio nombre del fichero ejecutable (en este caso ls) se dice que es el argumento número 0.

    Los programas también devuelven un valor al sistema operativo. Para conocer qué valor ha devuelto un programa, hay que dar justo a continuación de haber ejecutado el programa la orden echo $? a la shell:
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ ls -l
    total 132
    -rw-r--r--   1 gyermo     profes         135 Feb 16 12:29 makefile
    -rwxr-xr-x   1 gyermo     profes       61440 Feb 16 12:37 prueba
    [...]
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ echo $?
    0
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ ls -l NoWomanNoCry.mp3
    NoWomanNoCry.mp3 not found
    <T>/usuarios/gyermo/PRIVADO/SO/PRACTS/PRUEBA$ echo $?
    2           
    El valor devuelto por un programa ha de ser un número comprendido entre 0 y 255. Es costumbre en UNIX que un valor de 0 signifique ejecución exitosa y los valores mayores que cero indiquen error.

  6. El prototipo de main.

    main es la primera función que se ejecutará dentro de un programa. Todo ejecutable debe contener una función main. El prototipo es variable, sin embargo. Si definimos el prototipo de la función main de la manera siguiente, podemos saber qué argumentos nos ha pasado el usuario en esta ejecución y devolver un valor al sistema operativo:
    int main(int argc, char *argv[]);
                
    El valor que devolveremos al sistema operativo será justo ese entero que devuelve la función main. Los argumentos los recibiremos en los parámetros con los que el sistema operativo va a invocar a la función main cuando comience la ejecución del programa.

    El primer parámetro es un entero e indica cuántos argumentos ha tecleado el usuario, incluyendo el propio nombre del programa. El segundo parámetro es un array de cadenas de caracteres de longitud igual al número de argumentos y que contiene los propios argumentos en sí.

    Ejemplo: la función main del programa ls recibe los siguientes parámetros cuando un usuario teclea "ls -l":

    Argumentos de main para ls -l
    argc2
    argv[0]"ls"
    argv[1]"-l"

    Nota: al ser argc y argv parámetros de una función (la función main), son variables mudas, es decir, no tienen por qué llamarse así. Lo que importa es que coincida su tipo. De todos modos, es costumbre en C denominarlos así.

  7. Las llamadas al sistema.

    Manejar bien las llamadas al sistemas es un objetivo muy muy importante en esta asignatura. Una llamada al sistema tiene el aspecto de una función de C. Sin embargo, se trata de una auténtica invocación al núcleo del sistema operativo para que realice una tarea para nuestro programa. En cada sesión se presentarán unas cuantas llamadas al sistema para vuestro estudio.

    Para usar una llamada al sistema en vuestros programas sólo debéis conocer el nombre de la llamada, qué parámetros hay que pasarle, qué devuelve y el fichero de cabecera o los ficheros de cabecera que tenéis que incluir en vuestro programa.

    Las llamadas al sistema de cada sesión las podréis encontrar aquí. Este fichero se os dejará el día del examen. Es conveniente que lo manejéis con soltura. Para una descripción detallada de lo que hace la llamada al sistema, debéis consultar la página de manual de la llamada. Por ejemplo, man -s 2 chmod. El -s 2 viene de que todas las llamadas al sistema se encuentran en la sección 2 del manual.

    Ejemplo: si queremos cambiar los permisos del fichero pepe.txt para que todo el mundo tenga acceso de lectura y escritura a él, la llamada al sistema sería:
    #include <sys/types.h>
    #include <sys/stat.h>
    [...]
    chmod("pepe.txt",0666);
                
    Todas las funciones de biblioteca de C (p. ej. printf), se basan internamente en las llamadas al sistema y sus páginas de manual se encuentran en la sección 3c.

  8. Condiciones de error.

    Una llamada al sistema puede fallar. Por ejemplo, la llamada al sistema del apartado anterior puede fallar porque el fichero pepe.txt no exista, porque no tengamos los permisos adecuados para cambiar los permisos del fichero, etc. Es responsabilidad del programador detectar cuándo se ha producido un error. Normalmente sabemos que se ha producido un error porque la llamada al sistema devuelve un valor concreto, habitualmente -1 (menos uno). En cualquier caso, se puede consultar el resumen o las páginas de manual. Por lo tanto, mejor que el código del apartado anterior deberíamos poner algo así:
    #include <sys/types.h>
    #include <sys/stat.h>
    [...]
    if (chmod("pepe.txt",0666)==-1)
       {fprintf(stderr,"No se puede cambiar los permisos.\n");
        return 1;}
                
    Para saber qué tipo de error se ha producido, debemos consultar una variable global del sistema denominada errno. En la página de manual de la llamada al sistema con la que estemos trabajando se nos dice qué valores toma errno según el error que se produzca. En particular, en la página de manual de chmod podemos leer:
    [...]
     ERRORES
          Si chmod() o fchmod() fallan, el modo del fichero sigue igual. A errno
          se le asigna uno de los siguientes valores.
    [...]
               [ENOENT]            Un componente de path o el fichero nombrado
                                   por path no existe.
    [...]
                
    Por lo tanto, si queremos considerar ese error en concreto, el código quedaría:
    #include <sys/stat.h>
    #include <errno.h>
    [...]
    if (chmod("pepe.txt",0666)==-1)
       {if (errno==ENOENT)
            fprintf(stderr,"El fichero pepe.txt no existe.\n");
        else
            fprintf(stderr,"Imposible cambiar los permisos debido a un error.\n");
        return 1;}
                
    Las acciones que el programa debe tomar si se produce un error pueden variar. Puede ser que el programa se pueda recuperar del error o puede que tenga que acabar su ejecución. En todo caso, es el programador el que debe situarse en las circunstancias de cada error y decidir. En el caso del ejemplo, decidimos acabar el programa y devolver 1 al sistema operativo.

  9. La función de biblioteca perror.

    Como considerar todos y cada uno de los posibles errores de una llamada al sistema sería una labor muy tediosa y costosa, existe una función de biblioteca de C que nos ahorra todas estas comprobaciones. La función perror comprueba la variable errno y escribe por el canal de error estándar del programa una etiqueta que le pasamos como parámetro, dos puntos y un mensaje indicativo del error que se ha producido. La etiqueta suele hacer referencia al nombre del programa, a la función dentro del programa o cualquier otra referencia que sirva al programador para detectar en su código fuente dónde se produjo el error. Aunque es una función muy útil, hay veces que no aporta toda la información deseada.

    El código del apartado anterior puede quedar así usando la función perror:
    #include <sys/stat.h>
    #include <stdio.h>
    [...]
    if (chmod("pepe.txt",0666)==-1)
       {char etiqueta[80];
        sprintf(etiqueta,"%s:chmod:pepe.txt",argv[0]);
        perror(etiqueta);
        return 1;}
                


  10. Práctica.

    Como primera práctica (que no hay que entregar), hay que realizar un programa que admita el nombre de un fichero como argumento. El programa debe cambiar el grupo al que pertenece el fichero al grupo cuyo identificador de grupo es el 666. El programa debe detectar e imprimir las codiciones de error y devolver 0 al sistema operativo si no se produjeron errores y 1 en caso contrario. Notas: en caso de que el fichero sea un enlace simbólico, debe cambiar el grupo del propio enlace, no de aquello a lo que apunta. El propietario del fichero debe permanecer inalterado.

    Soluciones y comentarios.

  11. Órdenes de la shell relacionadas.

    chmod
    modifica los permisos de un fichero
    chown
    cambia el propietario de un fichero
    chgrp
    cambia el grupo de un fichero
    ln
    hace un enlace duro o simbólico a un fichero
    rm
    borra un fichero
    ls
    lista el contenido de un directorio


  12. Funciones de biblioteca relacionadas.



  13. LPEs.


© 2011 Guillermo González Talaván.