SISTEMAS OPERATIVOS II

Tercer curso Ingeniería Informática. Curso 2005-2006

Práctica 1: Procesos en UNIX.

Comenzar la codificación de un intérprete de comandos (shell) en UNIX, que se irá completando en suscesivas prácticas. Dicho intérprete incluirá de momento los comandos que se citan a continuación. Los argumentos entre corchetes [] son opcionales. Los argumentos separados por | indican que debe ir uno u otro, pero no ambos simultaneamente. No debe dilapidar memoria (ejemplo: variable que se asigna cada vez que se llama a una función y no se libera). Cuando el shell no pueda ejecutar una acción por algún motivo, debe indicarlo con un mensaje como el que se obtiene con sys_errlist[errno] o con perror() (por ejemplo, si no puede cambiar de directorio debe indicar por qué). En ningún caso debe producir un error de ejecución. Las direcciones de memoria deben mostrase en hexadecimal. La información que se nuestra en pantalla no debe incluir en ningun caso líneas en blanco. El shell leerá de su entrada estándar y escribirá en su salida estándar, de manera que podría ser ejecutado un archivo de comandos invocando el shell con su entrada estándar redireccionada a dicho archivo.

autores
Indica los nombres y los logins de los autores de la práctica.

fin
Termina la ejecución del intérprete de comandos.

exit
Termina la ejecución del intérprete de comandos.

chdir [dir]
Cambia el directorio actual a dir. Si no se le suministra argumento informa del directorio actual.

prompt prompt
Cambia el indicador (prompt) del intérprete de comandos.

ruta [-a|-d|-n|-p] [dir]
Manipula la ruta de búsqueda del intérprete de comandos.

La ruta de búsqueda del intérprete de comandos es el conjunto de directorios donde el shell busca los ejecutables (Su misión es análoga a la variable de entorno PATH en el shell del sistema). NO DEBE implementarse con una variable de entorno. Los directorios se especificarán sin el caracter '/' al final Ejemplos

 #ruta -a /usr/local/bin /* correctos */
 #ruta -a /
 #ruta -a .
 ......
 #ruta -a /usr/local/bin/ /*incorrecto*/
 #ruta -a ./              /*incorrecto*/

ruta -a dir
Añade dir a la ruta de búsqueda.
ruta -d dir
Elimina dir de la ruta de búsqueda.
ruta -n
Vacía la ruta de búsqueda.
ruta -p
Añade los directorios de la variable de entorno PATH a la ruta de búsqueda.
ruta dir
Indica si dir está en la ruta de búsqueda.
ruta
Muestra la ruta de búsqueda.

cual ejecutable
Busca ejecutable en la lista de directorios que constituyen la ruta de búsqueda del intérprete de comandos y devuelve la trayectoria completa hasta él (análogo al comando which del sistema). Si no lo encuentra lo indicará. Si se le indica una trayectoria completa (empezando por ., por / o por ..) indicará si dicho fichero existe o no

#ruta -a /usr/openwin/bin
#cual xterm
/usr/openwin/bin/xterm
#cual xternp
 xternp: no encontrado
#cual ./aa.out
 ./aa.out: no encontrado
#cual ./a.out
 ./a.out

getpid
Devuelve el pid del proceso y de su proceso padre.

fork
El intérprete de comandos crea un hijo con fork() y se queda (el propio intérprete de comandos) en espera hasta que dicho hijo (el creado con fork) termine. El hijo inicializa su lista de procesos en segundo plano a vacía.

exec com
El intérprete de comandos ejecuta, sin crear un nuevo proceso (reemplaza su código), el programa especificado en com. com representa un ejecutable con sus parámetros. Para poder ser ejecutado, dicho ejecutable debe residir en uno de los directorios de la ruta de búsqueda del intérprete de comandos (ruta)o bien especificarse la trayectoria completa hasta él (comenzando por /, . o ..). Debe usarse la llamada al sistema execv.

Ejemplo

#exec /usr/bin/ls -l /home  /*ejecuta /usr/bin/ls*/
  ....
#exec ./a.out -l /*ejecuta a.out, 
                 /*que esta en el directorio actual */
......
#exec ls -l   /* para ejecutar esto, es necesario */
              /*que el directorio  /usr/bin,  */
              /*donde esta el programa ls, se haya incluido */
              /* a la ruta de busqueda */

comando
Totalmente análogo al comando exec, salvo que el shell crea el proceso que ejecuta dicho comando y espera a que termine (la ejecución es, por tanto, en primer plano). Todo lo dicho sobre los ejecutables en el comado exec es aplicable aquí .

Ejemplo

#/usr/bin/ls -l /home  /*crea un proceso que ejecuta /usr/bin/ls*/
....
#./a.out -l   /* crea un proceso que ejecuta a.out,*/
......        /* que esta en el directorio actual    */
#ls -l        /* para ejecutar esto, es necesario que el directorio */
              /* /usr/bin, donde esta el programa ls, se haya incluido */
              /* a la ruta de busqueda */
.

com &
Análogo a com pero la ejecución es en segundo plano (el shell no espera a que el proceso termine).. Afecta a tanto a comando como a LV comando. Ejemplos

 
#xterm -e csh &

crea un proceso que ejecuta xterm en segundo plano.

procs [-n|-s|-a]
Muestra una lista de los procesos que ha mandado este shell en segundo plano. (dicha lista es mantenida por el propio shell). Para cada proceso debe indicar, la línea de comando con que fue lanzado, la hora a la que se inició, y el estado (activo, terminación normal, terminación debido a una seņal), asi como el valor devuelto (o la señal en caso de parado o terminado debido a una señal). El listado debe imprimir SOLO UNA LINEA POR CADA PROCESO. Las opciones -n, -s y -a se utilizan para eliminar de la lista los procesos que ya hayan terminado: la opción -n elimina de la lista los procesos que hayan terminado normalmente, la opción -s los que hayan terminado debido a una señal y la opción -a todos los que hayan terminado.

recursiva [-a|-n|-d] n
Invoca a la función recursiva n veces, la opción -a, -n o -d indica si la memoria asignada con malloc en dicha función debe liberarse (a)ntes de la siguiente llamada recursiva, (d)espués o (n)o liberarse. Si no se indica una opción se supone que la memoria se libera despues de la llamada (-d). La función recursiva recibe dos parámetros: uno que indica el número de veces que se tiene que invocar y otro que indica cuando liberar la memoria asignada con malloc; tiene 3 variables, un array automatico de 512 caracteres, un array estático de 512 caracteres y un puntero a caracter.

Esta función debe hacer lo siguiente

  1. asignar memoria (mediante malloc) al puntero para 512 caracteres.
  2. imprimir
    • el valor y la dirección del parámetro que recibe.
    • el valor y la dirección del puntero.
    • la dirección de los dos arrays (el nombre del array como puntero).
  3. si se ha especificado la opción -a liberar la memoria asignada al puntero.
  4. invocarse a si misma con (n-1) como parámetro (si n>0).
  5. si se ha especificado la opción -d liberar la memoria asignada al puntero.

Un posible código pra la función recursiva (sin las definiciones de constantes)podría ser:

void recursiva (int n, int liberar)
{
char automatico[TAMANO]; 
static char estatico[TAMANO]; 
void * puntero;

puntero=(void *) malloc (TAMANO);
printf ("parametro n:%d en %p\n",n,&n);
printf ("valor puntero:%p en direccion: %p\n", puntero,&puntero);
printf ("array estatico en:%p, array automatico en %p\n", estatico,automatico);
if (liberar==ANTES)
   free (puntero);
if (n>0)
   recursiva(n-1,liberar);
if (liberar==DESPUES)
   free (puntero);
}

direcciones [-f|-v]
Imprime las nombres y las direcciones de las funciones que implementan los comandos del shell (-f), de las variables globales (-v). Si no se especifica ni -f ni -v imprime las direcciones de las funciones y de las variables globales.

Información detallada de las llamadas al sistema y las funciones de la librería debe obternerse con man (exec, chdir, fork, strtok, waitpid, getpid..)

FORMA DE ENTREGA Va a ser utilizado el servicio de recogida de prácticas suministrado por el Centro de Cálculo de esta Facultad y parte del proceso de corrección de las prácticas va a ser automtico (compilación, listado de practicas entregadas etc) por lo cual deben entregarse exactamente como se indica a continuación:

FECHA DE ENTREGA VIERNES 21 ABRIL 2006