Sistemas operativos

Electrónica. Ficheros Unix. Procesos y programación Shell. Manejo de directorios. Gestión de procesos: intercomunicación

  • Enviado por: Ángel Labrador
  • Idioma: castellano
  • País: España España
  • 39 páginas
publicidad

LABORATORIO DE SISTEMAS OPERATIVOS

PRÁCTICA 1

  • ¿Qué ocurre si se introducen contraseñas de menos de 6 caracteres? ¿Y si no se introduce ningún carácter numérico o especial?

  • Lo que ocurre es que el sistema no te deja que tengas ese password y te pide que introduzcas otro mayor de seis letras y con caracteres especiales.

  • Averiguar cuantos ususarios están conectados en el sistema. ¿Qué orden emplea? Describir el siginficado de los campos mostrados por pantalla por esa orden.

  • Utilizamos la orden who. Los campos mostrados son:

    • Name: da los nombres de onexión del usuario.

    • Line: indica la línea o el terminal que se está utilizadno, dentro de los identificados en el directorio /dev.

    • Time: da el tiempo de conexión del usuario.

    Tambien podemos utilizar la opción -q, la cual solo visualiza los nombres y el número de usuarios, ignorando las otras opciones.

  • ¿Qué tipo de sistema operativo UNIX hay en el laboratorio? ¿Sobre que máquina se ejecuta?

  • Tenemos el Linux Red Hat ejecutándose sobre cada máquina.

  • ¿Cuál es la diferencia entre la utilización de \r, \n, \c en al orden echo? ¿Para que pueden servir? Explicarlo con ejemplos.

  • \r: Carácter de retorno de carro (ir al comienzo de la línea actual).

    \n: Carácter de nueva línea (ir al comienzo de la nueva línea).

    \c: Imprime argumentos hasta ese punto, eliminando la nueva línea e ignorando los argumentos restantes.

    Sirven para dar distintas opciones de impresión en pantalla para el usuario.

  • ¿Para que sirve la opción -k de la orden man? ¿Qué diferencia hay entra las órdenes man -k users y man users?

  • Es equivalente al comando apropos, y este sirve para buscar un conjunto de ficheros de la base de datos que contengan una breve descipción de comandos del sistema para palabras clave y muestra el resultado en la salida estandar.

    Con la orden man -k users, se nos muestra una descipción de comandos que contengan la palabra users y una breve descripción de su función. Con la orden man users, tenemos la página del manual del comando users.

  • Con ayuda de la opción anterior del man, averigurar el contenido y los campos del fichero passwd. ¿Es lo mismo el fichero que la orden passwd?

  • No. La orden sirve para cambiar el password, mientras que el fichero almacena los datos relativos al password de cada usuario.

    1.10.Para qué se utiliza la orden tty.

    Se utiliza para obtener la vía de acceso del terminal actual de usuario.

    PRACTICA 2:

    Estructura Interna del Sistema de Ficheros Unix

    2.1. Averiguar cual es su directorio de conexión y crear en él un directorio que se llame p02.

    Tecleando pwd obtenemos : /home/telematica/tel24

    Para crear el directorio: mkdir p02

    2.2. Copie el fichero passwd del sistema en el directorio p02. Realice la copia de modos distintos:

  • Especificando tanto el origen como el destino mediante trayectorias absolutas

  • cp /etc/passwd /users/so/telematica/tel24/p02/passwd

  • Especificando origen y destino con trayectorias relativas.

  • Desde el directorio p02: cp /etc/passwd passwd

    2.3. Sin conectarse a al máquina alpha localice el fichero passwd y tráigaselo a su directorio de trabajo.

    Localizamos el fichero y obramos como en el apartado anterior.

    2.4.

  • Cree un enlace fuerte a un fichero situado en su directorio de conexión y compare el número de enlaces que tiene ahora y los que tenía antes de realizar esta operación.

  • Tecleamos ln /etc/mtab pepe. Al ver los enlaces antes teníamos 1 y ahora hay 2.

  • Realice de nuevo la misma operación pero en este caso sobre un directorio. ¿Puede realizar un enlace blando sobre un directorio?

  • No se puede realizar. El blando si se puede ln -s p02 pepe

  • Cree un enlace blando sobre el fichero original de la pregunta a) ¿Cuántos enlaces tiene ahora?

  • Tecleamos ln -s /etc/mtab pepe. Al ver los enlaces hay 2, los mismos.

  • Borre el fichero original. ¿Puede acceder a los datos a través del soft-link? ¿y a través del hard-link? ¿Qué ocurre si creamos un fichero con el mismo nombre que el que hemos borrado? ¿Puede acceder a los datos del sfot-link? ¿y a través del hard-link?

  • Si accedemos a través del hard-link podemos acceder al fichero original aunque esté borrado. Si accedemos a través del soft-link no podemos acceder al fichero original si está borrado. Si creamos un fichero con el mismo nombre que el que habíamos borrado podemos volver a acceder a la información.

  • Intente realizar un enlace fuerte sobre el fichero de contraseñas del sistema. ¿Qué ocurre? ¿Por qué? Realice un enlace blando. ¿Qué ocurre? ¿Por qué?

  • Nos deja hacerlo siempre.

    2.5.

    ¿Es el mismo para todos?

    ¿Se puede cambiar?

    Directorio /

    SI

    NO

    Directorio .

    Depende donde estemos

    Directorio ~

    NO

    SI

    2.6.

  • Cree un directorio que se llame D1 colgando de su directorio de conexión. ¿Con que permisos se crea.

  • drwxrwxr-x

  • Cambie los permisos con umask de forma que estén activados todos menos los de ejecución. Cree otro directorio hermano de D1 llamado D2. ¿Qué permisos tiene?

  • umask 111

    permisos: drw-rw-rw

  • En el directorio D2 cree un fichero con los permisos ----------. ¿Lo puede borrar?

  • umask 777

    No se puede borrar.

  • Intente borrar el fichero que pertenece a otro usuario.

  • No se puede.

  • Ponga todos los permisos del D2 a d--------. ¿Puede acceder a él? Active el de ejecución, ¿puede acceder a él? Active también el de escritura, ¿puede acceder y ver su contenido? Active para el directorio D2 los permisos de ejecución y lectura únicamente ¿puede acceder al directorio? ¿puede borrar un fichero que tenga los permisos de escritura activados?

  • chmod 000 d2

    Se puede acceder siempre a él.

    chmod 555 d2

    No se puede borrar aunque tenga los permisos de escritura activados

  • Con que permisos se crea un directorio o fichero

  • Se crea con los especificados en la orden umask.

  • De que depende que se pueda borrar un directorio o fichero.

  • De los permisos que tenga activados, y en el caso de ficheros también depende de los permisos que tenga activados el directorio donde esté ubicado.

    2.7. Listar todos los ficheros del directorio /etc que comiencen por i y terminen por b. ¿Qué ficheros tiene como segunda letra una s? ¿Qué ficheros tiene como tercera letra una consonante?

    Estando en el directorio etc:

    ls i*b

    ls ?s*

    ls ??[! a e i o u]*

    2.8. ¿Sería posible copiar con una única orden el directorio p02 en el directorio bin?

    cp -r p02 bin

    2.9. hacer un listado largo de todos los ficheros del directorio de conexión pero de modo que no muestre el propietario sino exclusivamente el grupo y que añadan una / tras los ficheros de directorio.

    ls -l -o -F

    2.10. ¿Cómo se podría paginar la salida de la orden anterior para que se pudiera ver el resultado más cómodamente por pantalla?

    ls -l |more

    PRÁCTICA 3:

    Procesos y programación Shell

    4.1. Explique que ocurre en los siguientes casos:

    • Envíe las señales 15 y 9 (en este orden) a la shell que le atiende.

    Con la orden kill -15 PID no ocurren nada.

    Con la orden kill -9 PID se sale la shell.

    • Envíe la señal 15 al proceso padre de la shell que le atiende

    El proceso padre termina con kill -15 PID.

    • Ejecute ahora la orden sleep 300 en background y envíe de nuevo las señales 15 y 9 a este nuevo proceso.

    Con la orden kill -15 PID el proceso termina controladamente (termined).

    Con la orden kill -9 PID el proceso acaba abruptamente (killed).

    4.2. ¿Qué hace la siguiente pipeline? who | wc -l

    who -> lista los usuarios conectados

    wc -> cuenta el número de líneas de un fichero

    Por lo tanto, el comando contará el número de usuarios conectados y lo mostrará por la salida estándar.

    4.3. Explicar qué hacen y qué diferencias existen entre las siguientes secuencias de ordenes:


    CONEXIÓN=$HOME

    echo $CONEXIÓN

    ksh

    echo $CONEXIÓN

    ^D

    echo $CONEXIÓN

    CONEXIÓN=$HOME

    export CONEXION

    echo $CONEXIÓN

    ksh

    echo $CONEXIÓN

    CONEXION=/tmp

    ^D

    echo $CONEXION


    En el primer caso guardamos el directorio de conexión en la variable CONEXIÓN. Después cambiamos de shell y en esta shell no tenemos información de la variable almacenada en la primera. Regresamos a la primera shell y observamos que todavía está almacenado el valor.

    En el segundo caso exportamos el valor de la variable a cualquier shell que vayamos a abrir. Al abrirla vemos que ahora si sabemos el valor de la variable. Este valor lo modificamos y salimos a la primera shell, aquí el valor de la variable es el inicial.

    4.4. Mediante el editor vi realice un shell script que cuente el número de ficheros que hay en el directorio de conexión. Explique detalladamente todos los pasos.

    CONEX=$HOME

    echo Directorio de conexión $CONEX

    cd /$CONEX

    NUMERO=`ls -l | wc -l `

    echo El numero de ficheros es $NUMERO

    Primero hallamos el directorio de conexión, por si llamamos al programa desde otro lado nos vamos la directorio de conexión, a continuación mostramos una lista detallada (1 línea por fichero) contamos las línea y lo guardamos en un variable que después mostramos por pantalla.

    4.5. Debido a un fallo del administrado del sistema las órdenes vi y cp han sido borradas. ¿Podrá copiar el fichero /etc/passwd en su subdirectorio p4 sin la ayuda de esas órdenes?

    Si, con la orden cat /etc/passwd > passwd desde el directorio p04.

    4.6. Realice un programa shell que reciba como parámetros tres palabras y las muestre en pantalla ordenadas alfabéticamente.

    echo $1 > fichero

    echo $2 >> fichero

    echo $3 >> fichero

    sort -d fichero

    rm fichero

    4.7. El fichero /etc/passwd contiene información administrativa sobre los usuarios del sistema; en particular contiene los nombres de los usuarios dentro del sistema y en la vida real. Desarrollar un programa que muestre en pantalla un listado de los nombres, de usuario y reales, existentes en ese fichero.

    cut -f 1,5 -d':' passwd

    Los campos que nos interesan son el 1 y el 5 y están delimitados por el símbolo “:”.

    4.8. Desarrolle un shell script que reciba dos parámetros, un directorio y una cadena de caracteres a buscar en todos los ficheros regulares que se encuentren en el directorio especificado.

    cd /$1

    echo $2 > patron

    grep -f patron *

    rm -f patron

    4.9. Escribir un shell script que de manera perpetua añada cada 5 segundos una línea al fichero usuarios con la siguiente información:

    fecha | nº de usuarios conectados en ese instante | lista de los nombres de los usuarios

    while true

    do

    fecha=`date`

    numero=`who | wc -l`

    usuario=`who -q | cut -f 1 -d'#'`

    echo $fecha `|' $numero `|' $usuario >> usuarios

    sleep 5

    done &

    4.10. Desarrolle un shell script de nombre matador que reciba como parámetro el nombre de un proceso en ejecución y lo elimine, mostrando además un mensaje.

    ps > fich

    grep $1 fich > fich1

    pid=`cut -d “ “ -f1 fich1`

    rm -f fich fich2

    kill $pid

    echo el proceso $1 con PID $pid ha sido eliminado

    Determine el comportamiento del script en las siguientes situaciones:

    • Hay más de un proceso cuyo nombre coincide con el pasado como parámetro.

    Elimina todos los procesos

    • El parámetro es ps.

    • El parámetro es sh.

    PRÁCTICA 5:

    Llamadas al sistema para el manejo de directorios

    El objetivo de esta práctica es el desarrollo de una función:

    enlaces fich1 [fich2 ... fichN] path

    Su función localizar en el directorio path los enlaces fuertes que existan de los ficheros pasados como parámetros.

    A continuación mostramos los ficheros enlaces.c y hardlinks.c. El primero contiene el código principal (main) y la llamada a la función mostrar_enlaces_fuertes, contenida en el segundo fichero.

    /*---------------------------------------------------------------------------

    PRACTICA 5 PRACTICA 5 PRACTICA 5 PRACTICA 5 PRACTICA 5 PRACTICA 5

    ---------------------------------------------------------------------------

    ENLACES.C

    El programa realiza la busqueda en un directorio pasado como parametro y en

    los subdirectorios que cuelgan del mismo, los enlaces que haya de los

    ficheros indicados.

    Necesita el modulo hardlinks.c

    -------------------------------------------------------------------------*/

    #include <fcntl.h>

    #include <stdio.h>

    #include <dirent.h>

    #include <sys/stat.h>

    main (int argc, char *argv[])

    {

    int inodo=0; /* Numero de inodo del fichero tratado */

    int i; /* Variable para indexar la tabla */

    struct stat *stat_fichero; /* Variable que almcena la estructura stat */

    stat_fichero=(struct stat*)malloc(sizeof(struct stat));

    /* Comprobacion de la linea de comando */

    if (argc<3)

    {

    printf("Error \n Sintaxis: %s fich1 [fich2 ... fichN] path\n",argv[0]);

    exit(-1);

    }

    /* Para cada fichero introducido como parametro realizamos la busqueda */

    for (i=1;i<(argc-1);i++)

    {

    printf("\n ....COMIENZA LA BUSQUEDA PARA EL FICHERO %s....\n",argv[i]);

    stat(argv[i],stat_fichero);

    inodo=stat_fichero->st_ino;

    mostrar_enlaces_fuertes(argv[argc-1],inodo);

    printf("\n\n ...BUSQUEDA TERMINADA PARA EL FICHERO %s...\n\n",argv[i]);

    }

    free(stat_fichero);

    }

    /*---------------------------------------------------------------------------

    PRACTICA 5 PRACTICA 5 PRACTICA 5 PRACTICA 5 PRACTICA 5 PRACTICA 5

    ---------------------------------------------------------------------------

    HARDLINKS.C

    El programa realiza la busqueda en el directorio pasado como parametro y en

    los subdirectorios que cuelgan del mismo, los enlaces que haya del fichero

    indicado (mismo inodo).

    -------------------------------------------------------------------------*/

    #include <fcntl.h>

    #include <string.h>

    #include <stdio.h>

    #include <dirent.h>

    #include <sys/stat.h>

    #include <unistd.h>

    mostrar_enlaces_fuertes (char* path, int inodo)

    {

    char directorio[20];

    char nombre[20]; /*Almacena el path completo del fichero a tratar*/

    DIR *dir_des; /* Puntero a la ruta del directorio a abrir */

    struct dirent *entra_ddes; /* Entrada del directorio leido */

    int inodo_des=0; /* Numero de inodo del fichero tratado */

    struct stat *stat_f; /* Estructura del fichero leido */

    entra_ddes=(struct dirent *)malloc(sizeof(struct dirent));

    stat_f=(struct stat *)malloc(sizeof(struct stat));

    /* Abrimos el directorio */

    if ((dir_des=opendir(path))==NULL)

    {

    printf("\nError al abrir el directorio %s.\n",path);

    exit(-1);

    }

    /* Buscamos todos los enlaces fuertes del directorio */

    seekdir(dir_des,2);

    while ((entra_ddes=readdir(dir_des))!=NULL)

    {

    inodo_des=(entra_ddes->d_ino);

    if (inodo==inodo_des)

    {

    printf ("\nFichero de enlace en el directorio %s : %s",

    path,entra_ddes->d_name);

    }

    }

    rewinddir(dir_des);

    /* Leemos el directorio padre e hijo */

    readdir(dir_des);

    readdir(dir_des);

    /* Ahora comenzamos a buscar los subdirectorios */

    /* Para todas las entradas del directorio */

    while ((entra_ddes=readdir(dir_des))!=NULL)

    {

    strcpy(nombre,path);

    strcat(nombre,"/");

    strcat(nombre,entra_ddes->d_name);

    /* Leemos los datos y comprobamos si es un directorio */

    stat(nombre,stat_f);

    if ((stat_f->st_mode & S_IFMT)==S_IFDIR)

    {

    /* Hacemos la llamada a la funcion recursiva */

    mostrar_enlaces_fuertes(nombre,inodo);

    }

    }

    /* Cerramos el directorio */

    if (closedir(dir_des)==-1)

    {

    printf("\nError al cerrar el directorio %s\n",path);

    exit(-1);

    }

    free(entra_ddes);

    free(stat_f);

    }

    1.- Explicar los parámetros que reciben cada una de las llamadas al sistema.

    • DIR *opendir(char *dirname)

    Donde dirname es un puntero a la ruta del directorio que queremos abrir.

    • int closedir (DIR *dirp)

    Donde dirp es un puntero a uns estructura tipo DIR previamente abierta.

    • struct dirent *readdir (DIR *dirp)

    Donde dirp es un puntero a uns estructura tipo DIR previamente abierta.

    • void seekdir (DIR *dirp, long loc)

    Donde dirp es un puntero a uns estructura tipo DIR previamente abierta, y loc que es el valor de la entrada que queremos que apunte el puntero de lectura.

    • void rewinddir (DIR *dirp)

    Donde dirp es un puntero a uns estructura tipo DIR previamente abierta.

    • int stat (char *path, struct stat *buf)

    Stat devuelve, a través de buf, información sobre el estado del fichero cuya ruta es path. La estructura de buf es la siguiente:

    struct stat

    {

    dev_t st_dev; /* Numero de dispositivo donde se encuentra el fichero */

    ino_t st_ino; /* Nodo-i del fichero */

    ushort st_mode; /* 16 bits que codifican el modo del fichero */

    uid_t st_uid; /* UID del propietario del fichero */

    gid_t st_gid; /* GID del propietario del fichero */

    dev_t st_rdev; /* Major y minor numbers (solo para modos especiales) */

    off_t st_size; /* Tamaño en bytes de un fichero */

    time_t st_atime; /* Fecha del último acceso al fichero (lectura) */

    time_t st_mtime; /* Fecha de la última modificación del fichero */

    time_t st_ctime; /* Fecha del último cambio en el fichero */

    };

    2.- Codificar una comprobación adicional para determinar si alguno de los ficheros pertenece a algún sistema de ficheros diferente.

    Comprobacion (struct dirent *direc)

    {

    struct stat datos_fic; /* Estructura que almacena los datos del fichero */

    int ID_SISF=770; /* Identificador del sistema de ficheros */

    if (stat(direc->d_name,&datos_fic)==-1)

    {

    printf("\n Error al abrir el archivo %s",direc->d_name);

    exit(-1);

    }

    if (ID_SISF!=datos_fic.st_dev)

    {

    printf ("\nEL FICHERO %s NO PERTENECE AL SISTEMA DE ARCHIVOS\n",

    direc->d_name);

    exit(-1);

    }

    }

    Esta función se debe realizar cada vez que encontramos un fichero del cual queremos saber sus enlaces.

    El entero ID_SISF es una constante que indica el número del sistema de ficheros que queremos seleccionar para nuestras necesidades.

    LLAMADAS AL SISTEMA PARA LA GESTIÓN DE PROCESOS

    PROBLEMA 1

    Función items.c :

    Esta función se encarga de separar los comandos y parámetros en la línea de comandos, almacenándolos en un array de punteros a cadenas de caracteres. También indica si en la línea de comandos aparece el modo sumergido (&). La función devuelve un entero que indica el número de cadenas almacenadas en el array de punteros.

    #include <stdio.h>

    #include <string.h>

    /* comando : línea de comando a tratar

    linea : array de punteros a cadena de caracteres donde almacena

    las cadenas

    sumergido : indica si hay modo sumergido o no

    /* La función devuelve el número de cadenas almacenadas */

    int separaItems(char* comando,char **linea,int *sumergido)

    {

    int cont=0;

    linea [cont] = strtok (comando," ");

    if (linea[0]!=0) /*Para que no falle al darle al intro */

    if ( (strcmp (linea[cont],"&") ) ==0 ) /* Para que mire si el '&' es lo

    primero */

    {

    *sumergido=1;

    cont=-1; /* si es el primero lo tengo que borrar y preparar la lista

    para que el siguiente sea el 0 */

    }

    while (linea [cont++] != NULL)

    {

    linea [cont] = strtok (NULL," ");

    if (linea[cont]!=NULL)

    if ((strcmp(linea[cont],"&"))==0)

    {

    *sumergido=1;

    cont--;

    }

    }

    return(cont-1);

    }

    Programa microshell.c :

    Este es el programa principal que hace la función de una microshell .La función redireciones comprueba si existen algún tipo de redirecion. Si es así la ejecuta, y si no ejecuta el comando externo normalmente.

    #include <stdio.h>

    #include <fcntl.h>

    #include <string.h>

    #include <unistd.h>

    #include "items.h"

    int redirecciones(char **linea,int numero);

    void main(void)

    {

    char comando[100]; /* línea de comandos */

    char *linea[50]; /* array de punteros a cadenas de caracteres */

    int PID,numero,cont,sumergido=0;

    for (cont=0;cont<=50;cont++)

    {

    linea[cont]=(char *) malloc( (sizeof (char)) * 20);

    }

    system("clear");

    while (1)

    {

    printf("mi_prompt/>");

    gets(comando);

    /* Separación de la linea de comandos */

    numero=separaItems(comando,linea,&sumergido);

    if (linea[0] == 0 ) continue; /* Si se pulsa <ENTER> continua */

    /* Comprobación si es una de las tres ordenes internas */

    else if ((strcmp(linea[0],"exit"))==0) exit(0);

    else if ((strcmp(linea[0],"pwd"))==0) system(linea[0]);

    else if ((strcmp(linea[0],"cd"))==0)

    {

    if ((chdir(linea[1]))==-1)

    printf ("Error. El Directorio no existe. \n");

    }

    /* Si la orden es externa :

    Creación de un proceso hijo para ejecutar la orden externa */

    else

    {

    if (!(PID=fork())) /* CODIGO DEL HIJO */

    {

    redirecciones(linea,numero);

    exit(0);

    }

    /* Si no hay modo sumergido espera a que acabe el proceso hijo */

    else if (sumergido==0) wait(0);

    }

    }

    }

    int redirecciones(char **linea,int items)

    {

    int marca=0,f_entrada,f_salida;

    int a=1;

    /* Comprobación si existe redireción */

    for (a=0;a<items;a++)

    {

    /* Si hay redireción de entrada */

    if (strcmp(linea[a],"<")==0)

    {

    close(0);

    if ((f_entrada=open(linea[a+1],O_RDONLY))==-1)

    {

    printf("Error al abrir el fichero de entrada. \n");

    return(-1);

    }

    linea[a]=NULL;

    marca=1;

    break;

    }

    /* Si hay redireción de salida */

    else if (strcmp(linea[a],">")==0)

    {

    close(1);

    if ((f_salida=open(linea[a+1],O_WRONLY |O_CREAT,666))==-1)

    {

    printf("Error al abrir el fichero de salida. \n");

    return(-1);

    }

    linea[a]=NULL;

    marca=2;

    break;

    }

    }

    /* Ejecución de la orden externa */

    if ((execvp(*linea,linea))==-1 )

    printf ("Error en comando o nombre de archivo. \n");

    switch(marca)

    {

    case 1: close (f_entrada);break;

    case 2: close (f_salida);break;

    default:break;

    }

    }

    PROBLEMA 2

    Programa pro2.c :

    #include <stdio.h>

    #include <signal.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <unistd.h>

    void sigint_handler();

    main()

    {

    char texto[50];

    int fd_origen;

    int kk;

    int i=0;

    sigint_handler ();

    signal(SIGINT,sigint_handler);

    if (creat("pro2.xxx",0666)<0)

    {

    printf("\n No se pudo crear el fichero 'pro2.xxx'");

    exit(-1);

    }

    while(1)

    {

    if ((fd_origen=open("pro2.xxx",O_WRONLY | O_APPEND))==-1)

    {

    printf("\nNo se pudo abrir el fichero 'pro2.xxx'");

    exit(-1);

    }

    scanf("%s",&texto);

    while (texto[i]!='\0')

    {

    write(fd_origen,&texto[i],1);

    i++;

    }

    i=0;

    close(fd_origen);

    }

    printf("\nFIN\n");

    }

    void sigint_handler()

    {

    printf("TRATA\n");

    execv("pro22",NULL);

    exit(0);

    }

    Promgrama pro22.c :

    #include <stdio.h>

    #include <fcntl.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <unistd.h>

    main()

    {

    int fd_origen;

    char carac;

    char texto[50];

    int i=0;

    fd_origen=open("pro2.xxx",O_RDONLY);

    do

    {

    read(fd_origen,&carac,1);

    texto[i]=carac;

    i++;

    }while (carac!='\n');

    texto[i]='\0';

    printf("\nTEXTO %s\n",texto);

    }

    Fichero Makefile :

    microshell: microshell.c items.a

    cc -o microshell microshell.c items.a -L.

    items.a: items.c

    cc -c items.c

    ar r items.a items.o

    rm items.o

    PRÁCTICA 8:

    Intercomunicación de procesos

    PROBLEMA 1

    Esta práctica desarrolla un programa en C que da lugar a tres procesos que se comunican por medio de tuberías. El primer proceso (P1) debe abrir un fichero que le pasemos como argumento desde la línea de órdenes. os datos de este fichero serán enviados por medio de una tubería a un proceso P2 que se encargará de extraer los caracteres correspondientes a letras mayúsculas. Estos caracteres se enviarán a la pantalla y a un tercer proceso P3 (por medio de otra tubería) que se encargará de contar y visualizar por pantalla la cantidad total de letras mayúsculas.

    /*---------------------------------------------------------------------------

    PRACTICA 2 PRACTICA 2 PRACTICA 2 PRACTICA 2 PRACTICA 2 PRACTICA 2

    ---------------------------------------------------------------------------

    Este programa esta compuesto de tres procesos:

    * P1 realiza la lectura de un fichero introducido en la línea de comandos,

    y lo transmite caracter a caracter a traves de una tuberia.

    * P2 recoge la informacion transmitida por P1, selecciona las mayusculas,

    las saca por pantalla y las transmite por otra tuberia.

    * P3 recoge la informaci¢n transmitida por P2, cuenta el numero de caracte-

    res recogidos y los muestra por pantalla

    -------------------------------------------------------------------------*/

    #include <stdio.h>

    #include <fcntl.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    main(int argc, char *argv[])

    {

    char carac; /* caracter del fichero leido */

    char c_rec; /* caracter recibido */

    char mayus_rec; /* mayuscula recibida */

    char FIN='\0'; /* caracter de fin de transmision */

    int nbytes; /* cantidad de datos leidos del fichero */

    int fd_origen; /* identificador del fichero leido */

    int tuberia1[2]; /* tuberia de transmision de datos de P1 a P2 */

    int tuberia2[2]; /* tuberia de transmision de datos de P2 a P3 */

    int pid1, pid2; /* identificadores de los procesos creados */

    int contador=0; /* numero de mayusculas */

    /* Comprobacion de la linea de comandos */

    if (argc!=2)

    {

    printf("Error\n Sintaxis: %s fichero\n", argv[0]);

    exit(-1);

    }

    /* Abrimos la primera tuberia */

    if (pipe (tuberia1)==-1)

    {

    perror("Error al abrir la tuberia");

    exit(-1);

    }

    /* Abrimos el primer proceso hijo */

    if ((pid1=fork())==-1)

    {

    perror("Error al abrir el proceso hijo");

    exit(-1);

    }

    else if (pid1==0)

    {

    /* Este el primer proceso hijo */

    /* Abrimos la segunda tuberia */

    if (pipe (tuberia2)==-1)

    {

    perror("Error al abrir la tuberia");

    exit(-1);

    }

    /* Abrimos el segundo proceso hijo */

    if ((pid2=fork())==-1)

    {

    perror("Error al abrir el proceso hijo");

    exit(-1);

    }

    else if (pid2==0)

    {

    /* P3. El segundo proceso hijo */

    /* Leemos de la tuberia los datos transmitidos por P2 hasta el fin de

    transmision. Sacamos por pantalla los caracteres, y los contamos */

    printf("\nMAYUSCULAS RECIBIDAS: ");

    while (read(tuberia2[0],&mayus_rec,1)>0 && (mayus_rec!=FIN))

    {

    printf("%c",mayus_rec);

    contador++;

    }

    /* Sacamos por pantalla el numero de mayusculas */

    printf("\n\nNUMERO DE MAYUSCULAS RECIBIDAS: %d\n\n",contador);

    /* Cerramos las tuberias */

    close (tuberia1[0]);

    close (tuberia1[1]);

    close (tuberia2[0]);

    close (tuberia2[1]);

    printf("\nSe ha acabado P3\n");

    exit(0);

    }

    else

    {

    /* P2. El segundo proceso padre */

    /* Leemos de la tuberia los datos transmitidos por P1 hasta el fin de

    transmision. A continuacion seleccionamos las mayusculas, y estas

    las mostramos en pantalla y las transmitimos a P3 */

    printf("\n\nMAYUSCULAS ENVIADAS: ");

    while (read(tuberia1[0],&c_rec,1)>0 && (c_rec!=FIN))

    {

    if ((c_rec>='A')&&(c_rec<='Z'))

    {

    printf("%c",c_rec);

    if (write (tuberia2[1],&c_rec,1)<0)

    printf("Error al escribir en la tuberia21");

    }

    }

    /* Mandamos por la tuberia el fin de transmision */

    if (write (tuberia2[1],&FIN,1)<0)

    printf("Error al escribir en la tuberia22");

    /* Cerramos las tuberias */

    close (tuberia1[0]);

    close (tuberia1[1]);

    close (tuberia2[0]);

    close (tuberia2[1]);

    printf("\nSe ha acabado P2\n");

    exit(0);

    }

    }

    else

    {

    /* P1. Este es el primer proceso padre */

    /* Abrimos el fichero introducido en la linea de comandos */

    if ((fd_origen=open(argv[1],O_RDONLY))==-1)

    {

    printf("No se pudo abrir el fichero %s",argv[1]);

    exit(-1);

    }

    /* leemos el fichero y lo escribimos en la tuberia caracter a caracter */

    while ((nbytes=read(fd_origen,&carac,1))>0)

    {

    if (write (tuberia1[1],&carac,1)<0)

    printf("error en la trasmision por la tuberia11\n");

    }

    /* Mandamos por la tuberia el fin de transmision */

    if (write (tuberia1[1],&FIN,1)<0)

    printf("error en la trasmision por la tuberia12\n");

    /* Cerramos el fichero y las tuberias */

    close (fd_origen);

    close (tuberia1[0]);

    close (tuberia1[1]);

    printf("\nSe ha acabado P1\n");

    exit(0);

    }

    }

    PROBLEMA 2

    1.- Diagrama que muestre la jerarquía de procesos.

    2.- Diagrama de comunicación entre procesos.

    3.- Para los tres procesos, liberar las tuberías que se consideren oportunas para un funcionamiento correcto del programa.

    Vamos a mostrar el código que habría que introducir en los puntos indicados:

    /* 3.1 */

    close(master_line[0]);

    close(line_master[1]);

    /* 3.2 */

    close(master_line[1]);

    close(line_master[0]);

    /* 3.3 */

    close(slave_line[0]);

    close(line_slave[1]);

    /* 3.4 */

    close(slave_line[1]);

    close(line_slave[0]);

    /* 3.5 */

    close(master_line[1]);

    close(line_master[0]);

    close(slave_line[1]);

    close(line_slave[0]);

    /* 3.6 */

    close(master_line[0]);

    close(line_master[1]);

    close(slave_line[0]);

    close(line_slave[1]);

    4.- Tomando como base el código suministrado, realice las modificaciones necesarias para que los tres procesos sean independientes y se comuniquen empleando tuberías con nombre.

    Hemos separado el código de la siguiente manera:

    r1 -> master

    r2 -> slave

    r3 -> line

    /* .......................... R1 ............................... */

    #include <errno.h>

    #include <stdio.h>

    #include <fcntl.h>

    #include <math.h>

    #include <time.h>

    #include <string.h>

    #define LONG_MAX_MENSAJE 127

    #define MAX_INTENTOS 10

    #define ACK 0

    main()

    {

    int idesc,idlec;

    char mensaje[LONG_MAX_MENSAJE+1];

    int checksum;

    int i;

    int resp;

    int intentos;

    int longMensaje;

    if ((idesc=open("tmaster_e",O_RDWR))==-1)

    {

    printf("\Error al abrir la tuberia 'tmaster_e'");

    exit(0);

    }

    if ((idlec=open("tmaster_l",O_RDWR))==-1)

    {

    printf("\Error al abrir la tuberia 'tmaster_l'");

    exit(0);

    }

    printf("\n INTRODUCE EL TEXTO:\n");

    while (scanf("%s",mensaje)!=EOF)

    {

    intentos=MAX_INTENTOS;

    longMensaje=strlen(mensaje)+1;

    do

    {

    if(write(idesc,&longMensaje,sizeof(longMensaje))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if(write(idesc,mensaje,longMensaje)==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    for (i=0,checksum=0;i<longMensaje;i++)

    checksum += mensaje[i];

    if(write(idesc,&checksum,sizeof(checksum))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    intentos--;

    if(read(idlec,&resp,sizeof(resp))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    }while ((resp!=ACK)&&intentos);

    if (resp!=ACK)

    {

    printf("\nDemasiados errores en la linea. Terminando.\n");

    close(idesc);

    close(idlec);

    exit(2);

    }

    mensaje[0]=0;

    }

    close(idesc);

    close(idlec);

    }

    /* ............................. R2 .................................*/

    #include <errno.h>

    #include <stdio.h>

    #include <fcntl.h>

    #include <math.h>

    #include <time.h>

    #include <string.h>

    #define LONG_MAX_MENSAJE 127

    #define MAX_INTENTOS 10

    #define ACK 0

    main()

    {

    int idesc,idlec;

    char mensaje[LONG_MAX_MENSAJE+1];

    int longMensaje;

    int checksum;

    int checksumAct;

    int i;

    int resp;

    int nbytes;

    if ((idesc=open("tslave_e",O_RDWR))==-1)

    {

    printf("\nError al abrir la tuberia 'tslave_e'");

    exit(1);

    }

    if ((idlec=open("tslave_l",O_RDWR))==-1)

    {

    printf("\nError al abrir la tuberia 'tslave_l'");

    exit(1);

    }

    if ((nbytes=read(idlec,&longMensaje,sizeof(longMensaje)))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    while (nbytes)

    {

    mensaje[0]=0;

    if (read(idlec,mensaje,longMensaje)==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if (read(idlec,&checksum,sizeof(checksum))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    for(i=0,checksumAct=0;i<longMensaje;i++)

    checksumAct += mensaje[i];

    if(checksumAct!=checksum)

    resp=!ACK;

    else

    {

    resp=ACK;

    printf("\n MENSAJE RECIBIDO: %s\n",mensaje);

    }

    if (write(idesc,&resp,sizeof(resp))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if ((nbytes=read(idlec,&longMensaje,sizeof(longMensaje)))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    }

    close(idesc);

    close(idlec);

    }

    /* ............................ R3 ..................... */

    #include <errno.h>

    #include <stdio.h>

    #include <fcntl.h>

    #include <math.h>

    #include <time.h>

    #include <string.h>

    #define LONG_MAX_MENSAJE 127

    #define MAX_INTENTOS 10

    #define ACK 0

    main()

    {

    int idlec_m,idlec_s;

    int idesc_m,idesc_s;

    char mensaje[LONG_MAX_MENSAJE+1];

    int longMensaje;

    int checksum;

    int checksumAct;

    int i,k;

    int resp;

    int nbytes;

    if ((idlec_m=open("tmaster_e",O_RDWR))==-1)

    {

    printf("\nError al abrir la tuberia 'tmaster_e'\n");

    exit(0);

    }

    if ((idesc_m=open("tmaster_l",O_RDWR))==-1)

    {

    printf("\nError al abrir la tuberia 'tmaster_l'\n");

    exit(0);

    }

    if ((idesc_s=open("tslave_l",O_RDWR))==-1)

    {

    printf("\nError al abrir la tuberia 'tslave_l'\n");

    exit(0);

    }

    if ((idlec_s=open("tslave_e",O_RDWR))==-1)

    {

    printf("\nError al abrir la tuberia 'tslave_e'");

    exit(0);

    }

    srand((unsigned)time(NULL));

    if ((nbytes=read(idlec_m,&longMensaje,sizeof(longMensaje)))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    while (nbytes)

    {

    if (write(idesc_s,&longMensaje,sizeof(longMensaje))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    mensaje[0]=0;

    if (read(idlec_m,mensaje,longMensaje)==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if (read(idlec_m,&checksum,sizeof(checksum))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    k=rand()%10;

    if(k<3)

    {

    for (i=0;i<k+1;i++)

    mensaje[rand()%longMensaje]=32+rand()%96;

    if(k==3)

    checksum=rand()%longMensaje*128;

    }

    if (write(idesc_s,mensaje,longMensaje)==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if (write(idesc_s,&checksum,sizeof(checksum))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if (read(idlec_s,&resp,sizeof(resp))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if (write(idesc_m,&resp,sizeof(resp))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    if ((nbytes=read(idlec_m,&longMensaje,sizeof(longMensaje)))==-1)

    {

    perror(strerror(errno));

    exit(1);

    }

    }

    close(idlec_m);

    close(idlec_s);

    close(idesc_m);

    close(idesc_s);

    }

    Laboratorio de Sistemas Operativos

    39