

                    Descubriendo Linux Red Hat 5.0 (PARTE 2)
                    ------------ ----- --- --- --- ---------
                                 By Mr. Nuk3m  
                                 -- --- -----

 Hola a todos los que estan leyendo esto, yo soy Mr. Nuk3m y esta es la
 segunda entrega de este manual del sistema operativo Linux Red Hat 5.0.
 Disculpen las faltas de ortografia pero no voy a poner acentos, salvo las
 ees para que todos puedan leer este texto; ya sean usuarios de Windows o
 Linux :)  Me reservo los derechos de autor de este manual por lo que si
 quieren hacer modificaciones, avisen primero. Este texto es de libre
 distribucion, siempre y cuando aparezcan estas lineas y mi nombre,
 Mr. Nuk3m.

 A continuacion, como siempre, un indice para que puedas buscar lo que te
 interesa saber de Linux Red Hat 5.0:

  Contenido  
                
   Introduccion (lo esta leyendo)
                                      
   8. Utilidades Adicionales
      8.1  Utilidades de monitoreo
           8.1.1  date: Muestra la fecha y hora actuales
           8.1.2  who: Lista los usuarios logueados actualmente
           8.1.3  ps: Listado de los procesos
           8.1.4  free: Sumario de la utilizacion de la memoria
           8.1.5  top: Actividad del procesador
           8.1.6  df: Muestra el espacio libre en los sistemas de archivos
           8.1.7  du: Uso del disco
      8.2  Utilidades para trabajar con texto
           8.2.1  cat: Mostrar archivos
           8.2.2  head: Muestra el comienzo de un archivo
           8.2.3  tail: Muestra el final de un archivo
           8.2.4  ascii-xfr: Convierte archivos de texto
           8.2.5  more: Filtro para visualizacion de texto por pantalla
      8.3  Utilidades para agrupar y comprimir archivos
           8.3.1  gzip y bzip2: Compresion de archivos
           8.3.2  tar: Agrupa archivos
      8.4  Utilidades de ayuda
           8.4.1  man: Informacion de los comandos y utilidades
      8.5  Otras utilidades
           8.5.1  passwd: Cambiando el password
   9. Instalacion de software adicional
      9.1  Software distribuido con codigo fuente
           9.1.1  La distribucion
           9.1.2  La configuracion
           9.1.3  La compilacion
           9.1.4  El directorio /usr/local
           9.1.5  La instalacion
      9.2  El sistema de paquetes RPM
           9.2.1  Convenciones en los nombres de los paquetes
           9.2.2  La base de datos RPM
           9.2.3  Modos de operacion de rpm
      9.3  Utilizacion de librerias
           9.3.1  Directorios de las librerias
           9.3.2  Instalacion de librerias.
   10. Montando sistemas de archivos
     10.1  Sistemas de archivos y particiones
     10.2  Sintaxis del comando mount
     10.3  Montando sistemas de archivos
           10.3.1  Tipos de sistemas de archivos
     10.4  Desmontando sistemas de archivos
     10.5  El archivo /etc/fstab
           10.5.1  Campos de cada entrada
           10.5.2  Uso del archivo fstab
           10.5.3  Permitiendo montar sistemas de archivos a usuarios normales
   11. El kernel y los modulos
     11.1  Que es el kernel?
     11.2  La interaccion
           11.2.1  Las librerias del sistema
           11.2.2  Las utilidades del sistema
     11.3  Que son los modulos?
     11.4  Personalizando el kernel
           11.4.1  Eligiendo la configuracion adecuada
           11.4.2  Compilando el kernel
           11.4.3  Compilando los modulos
           11.4.4  Instalando los modulos
           11.4.5  Instalando el nuevo kernel
           11.4.6  Cargando y decargando los modulos
           11.4.7  Las dependencias entre los modulos
           11.4.8  Una carga de modulos mas inteligente
     11.5  Actualizando nuestro kernel
           11.5.1  Obteniendo el kernel
           11.5.2  Instalando las fuentes del kernel
   12. Aspectos avanzados de la shell
     12.1  Programas de la shell (scripts)
     12.2  Variables de la shell
           12.2.1  Exportando variables de la shell
           12.2.2  Variables automaticas de la shell
           12.2.3  Variables estandar de la shell
     12.3  El camino de busqueda (path)
     12.4  Caracteres especiales - "Quoting"
     12.5  Estado de salida de los comandos
     12.6  Los argumentos
     12.7  Estructuras de control
           12.7.1  Condicionales simples
           12.7.2  El condicional if
           12.7.3  Los loops condicionales while y until
           12.7.4  La sentencia for
           12.7.5  La sentencia case
     12.8  Evaluacion de condiciones - Test
     12.9  Evaluacion de expresiones - Expr


 CAPITULO 8

 UTILIDADES ADICIONALES

 8.1 UTILIDADES DE MONITOREO

 El S.O. Linux nos provee de un conjunto de utilidades que nos permiten
 monitorear nuestro sistema, desde enterarnos de la fecha actual hasta un
 sumario del uso de la memoria.

 8.1.1 date: MUESTRA LA FECHA Y LA HORA ACTUAL

 # date
 Sat May 29 23:54:23 ART 1999

 El comando date tambien se utiliza para setear la fecha y la hora del sistema,
 pero esto solo puede hacerlo el superusuario.

 8.1.2 who: LISTA LOS USUARIOS LOGUEADOS ACTUALMENTE

 El comando who muestra una lista de las personas que estan usando actualmente
 el sistema.

 # who
 tony     tty1   May 29 23:23
 root     tty2   May 29 20:15

 8.1.3 ps: LISTADO DE PROCESOS

 El comando ps muestra una lista de los procesos que se encuentran corriendo
 en el sistema. Usualmente este comando es utilizado por los programadores y
 los administradores del sistema para ver que es lo que esta sucediendo en el
 sistema. Los usuarios utilizan ps para averiguar el PID (process
 identification number) de los procesos errantes para poder matarlos.

 Si ejecutamos ps, veremos una lista formada por los procesos que nosotros
 estamos ejecutando, pero no veremos los procesos de otros usuarios. Vemos
 un ejemplo en la figura 8.1.

 En el listado que aparece como salida del comando ps vemos el PID, la
 terminal que lo controla, el estado del proceso, el tiempo de ejecucion y el
 comando que invoco al proceso. Los PIDs se asignan secuencialmente a medida
 que cada proceso comienza y ciclan otra vez hacia 1 cuando alcanzan 32767.
 Si un proceso se esta ejecutando en "background", podemos monitorearlo con
 el comando ps.

  # ps
    PID TTY STAT  TIME COMMAND
    491   1 S    0:00 /bin/login -- tony
    492   1 S    0:00 -bash
    503   1 S    0:00 sh /usr/X11R6/bin/startx
    504   1 S    0:00 xinit /home/tony/.xinitrx --
    508   1 S    0:02 wmaker
    509   1 S    0:06 kfm
    512   1 S    0:00 mount.app
    513   1 S    0:00 asclock -shape
    514   1 S    0:00 wmmixer -w
    515   1 S    0:00 wmmom
    516   1 S    0:00 wmmom -s
    521   1 S    0:23 emacs -fn 9x15
    525  p5 S    0:00 /bin/bash
    572  p6 R    0:00 ps

               Figura 8.1: Listando los procesos.

 Si ejecutamos ps aux veremos todos los procesos que se estan ejecutando en
 el sistema. Cada proceso tendra especificado el usuario dueo del mismo.

 8.1.4 free: SUMARIO DE LA UTILIZACION DE LA MEMORIA

 El comando free muestra la cantidad de memoria fisica utilizada y libre, la
 utilizacion del espacio "swap", la cantidad de memoria compartida y la
 utilizacion de los "buffers". La opcion -b muestra la cantidades en bytes,
 la opcion -k en kilobytes (es la predeterminada) y la opcion -m en megabytes.
 Vemos la salida de este comando en la figura 8.2.

  # free
             total       used       free     shared    buffers    cached
  Mem:       95696      70068      25628      39672       6840     28760
  -/+ buffers/cache:    34468      61228 
  Swap:      40156          0      40156

               Figura 8.2: Visualizando la informacion de la memoria utilizada
                           en el sistema.

 8.1.5 top: ACTIVIDAD DEL PROCESADOR

 El comando top provee una vision en tiempo real de la actividad del
 procesador. Nos muestra una lista de los procesos que utilizan el CPU de
 manera intensiva y provee una interfase interactiva para la manipulacion de
 los procesos. El comando top puede mostrar el listado de los procesos
 ordenados por el uso de CPU, utilizacion de memoria o tiempo de ejecucion.

 8.1.6 df: MUESTRA EL ESPACIO LIBRE EN LOS SISTEMAS DE ARCHIVOS

 El comando df (disk free) muestra el espacio disponible en cada sistema
 de archivos actualmente montado. La unidad utilizada es un bloque de 1K,
 pero podemos modificar esto invocando a df con la opcion -h (human) para
 que muestre la informacion del espacio disponible en un formato mas
 accesible. Vemos un ejemplo en la figura 8.3.

  # df
  Filesystem         1024-blocks  Used Available Capacity Mounted on
  /dev/hda3            1701926 1306039   307932     81%   /
  /dev/hda2             305064  200456   104608     66%   /mnt/win95
  /dev/hda1            2096450 1510124   586326     72%   /mnt/nt
  /dev/hdc1            2108544 1620352   488192     77%   /mnt/akenaton 
  # df -h
  Filesystem            Size  Used  Avail  Capacity Mounted on
  /dev/hda3             1.6G  1.2G   301M     81%   /
  /dev/hda2             298M  196M   102M     66%   /mnt/win95
  /dev/hda1             2.0G  1.4G   573M     72%   /mnt/nt
  /dev/hdc1             2.0G  1.5G   477M     77%   /mnt/akenaton 

            Figura 8.3: Visualizando el espacio disponible en los
                        sistemas de archivos.

 8.1.7 du: USO DEL DISCO

 El comando du (disk usage) nos sirve para averiguar cuanto espacio estan
 ocupando nuestros archivos. Cuando es invocado sin argumentos, du nos
 devuelve una lista con los subdirectorios del directorio actual y el
 espacio ocupado por cada uno de ellos. Vemos un ejemplo en la figura 8.4a.

  # pwd
  /home/tony/docs/linux
  # du
  1446 ./images
  137 ./xtras
  2114 .

         a. Visualizando el espacio ocupado por cada subdirectorio.

 Es usual querer saber cuanto espacio esta ocupando un directorio junto
 con todos sus subdirectorios. Para ello podemos utilizar el comando du
 con la opcion -s y como argumento el directorio en cuestion. Esta opcion
 realiza un sumario de espacio ocupado por cada argumento pasado al comando.
 Si no pusieramos la opcion -s el comando nos daria como salida un listado
 de los subdirectorios que se encuentran en ese directorio y el espacio que
 ocupan los mismos. Vemos un ejemplo de esto en las figuras 8.4b y c.

  # du -s Desktop
  14 Desktop

         b. Visualizando el espacio ocupado por un subdirectorio

  # du Desktop
  2 Desktop/Trash
  8 Desktop/Templates
  2 Desktop/Autostart
  14 Desktop

         c. Visualizando el espacio ocupado por los subdirectorios de un
            directorio.

          Figura 8.4: Visualizando el espacio ocupado por los archivos.

 8.2 UTILIDADES PARA TRABAJAR CON TEXTO

 8.2.1 cat: MOSTRAR ARCHIVOS

 El uso estandar de este comando es el de mostrar archivos en nuestra
 terminal. Ademas el comando cat se puede utilizar para concatenar archivos.
 Ejemplos en las figuras 8.5a y b.

  # cat /etc/printcap
  ##PRINTTOOL3## LOCAL cdj550 300x300 a4 {} DeskJet550 Default 1 1
  hp|lp:\
  :sd=/var/spool/lpd/hp:\
  :mx#0:\
  :sh:\
  :lp=/dev/lp0:\
  :if=8/var/spool/lpd/filter:

           a. Utilizando cat para ver el contenido de un archivo.

  # cat mess[123] > message
  # cat message
  Contenido del mensaje 1
  .....
  Contenido del mensaje 2
  .....
  Contenido del mensaje 3
  .....

           b. Utilizando cat para concatenar archivos.

 Otro uso muy comun de cat es en la creacion de archivos de texto con muy
 pocas lineas. A veces necesitamos crear archivos con muy pocas lineas
 de textos y no se justifica cargar un editor de texto para hacerlo. Si
 ejecutamos cat sin argumentos, el comando leera caracteres de la entrada
 estandar hasta encontrar un caracter de fin de archivo (Ctrl+D). Ejemplo en
 la figura 8.5c.

  # cat > /etc/motd
  Se recuerda a todos los usuarios que el espacio de disco que tiene
  asignado es como maximo 4MB.
  ^D

           c. Utilizando cat para crear archivos.

 8.2.2 head: MUESTRA EL COMIENZO DE UN ARCHIVO

 Hay ocasiones en las que queremos saber cual es el contenido de un archivo,
 pero no queremos visualizarlo todo, ya sea por que es muy grande y porque
 tardariamos mucho tiempo o porque se visualiza tan rapido que lo unico que
 vemos es una serie de flashs de caracteres en la pantalla. El comando head
 nos permite visualizar las primeras lienas de un archivo (10 por defecto).
 Usando la opcion -n <N> podemos visualizar las primeras N lineas del archivo.
 Vemos un ejemplo en la figura 8.6.

  # head -n 5 .x11amp/config
  [x11amp]
  allow_multiple_instances=FALSE
  always_show_cb=TRUE
  convert_underscore=TRUE
  conert_%20=TRUE

                Figura 8.6: Mostrando el comienzo de un archivo.

 8.2.3 tail: MUESTRA EL FINAL DE UN ARCHIVO

 El comando tail funciona de la misma forma que head, con la diferencia de
 que muestra las ultimas lienas de un archivo en vez de las primeras. Tambien
 visualiza 10 lineas por defecto, y soporta la opcion -n <N> para visualizar
 las N ultimas lineas del archivo. Veamos un ejemplo en la figura 8.7.

  # tail -n 5 /var/log/dmesg
   hdc: [PTBL] [523/128/63] hdc1
   NTFS version 990102
   VFS: Mounted root (ext2 filesystem) readonly.
   Freeing unused kernel memory: 48k freed
   Adding Swap: 40156k swap-space (priority -1)

                Figura 8.7: Mostrando en final de un archivo.

 8.2.4 ascii-xfr: CONVIERTE ARCHIVOS DE TEXTO.

 Linux se diferencia de otros S.O. en el tratamiento de los archivos de
 texto, mas especificamente en el formato del fin de linea. MS-DOS, Windows
 95/98 y NT identifican el fin de linea con 2 caracteres: LF (Line Feed) y
 CR (Carriage Return), avance de linea y retorno de carro respectivamente.
 Linux, en cambio identifica el fin de linea con un solo caracter LF (Line
 Feed).

 Por esto, un problema tipico es el de la transferencia de archivos de un
 sistema Linux hacia otro que entiende el fin de linea con 2 caracteres.
 Por ejemplo, si llevamos un archivo de texto de un sistema Linux a un
 sistema Windows y visualizamos su contenido, veremos que se encuentra
 todo el texto sobre una unica linea. Esto es porque no habia carateres de
 retorno de carro en el archivo y por lo tanto Windows no encontro ningun
 final de linea. Si en cambio, traemos un archivo de texto de Windows hacia
 Linux, tendremos un caracter de retorno de carro de mas por cada linea.

 La solucion a esto claramente no puede ser la edicion manual del archivo
 en cuestion, cosa que se puede volver inmediatamente tediosa y tiene
 asociada una alta probabilidad de error. La utilidad ascii-xfr es un
 filtro de archivos de texto que se ocupa de realizar estas traducciones
 de formatos de archivos de texto ASCII. Esta utilidad tiene dos modos de
 operacion:

  * Envio: En este modo se transmite el caracter de fin de linea como CR-LF.
           Se invoca con la opcion -s (Send).

  * Recepcion: Se elimina de cada fin de linea el caracter de CR. Se invoca
               con la opcion -r (Receive).

 Esta utilidad es invocada comunmente como un filtro, ya que lee de la
 entrada estandar (al recibir) y escribe en la salida estandar (al enviar),
 pero puede ser utilizada conjuntamente con redireccion de la entrada o la
 salida para lograr otros resultados.

 El siguiente comando crea una copia de un archivo del archivo de texto
 ascii-linux.txt en formato de Linux a ascii-win.txt en formato de texto
 de Windows; una vez ejecutado este comando, se creara el archivo
 ascii-win.txt y podra ser utilizado como un archivo de texto normal sobre
 Windows.

  ==> ascii-xfr -s ascii-linux.txt > ascii-win.txt

 El siguiente comando nos sirve para crear una copia en formato de texto
 Linux de un archivo de texto creado en Windows.

  ==> cat ascii-win.txt | ascii-xfr -r ascii-linux.txt

 8.2.5 more: FILTRO PARA VISUALIZACION DE TEXTO POR PANTALLA

 El comando more es un filtro para ver un texto pagina por pagina. Es
 utilizado normalmente para visualizar los contenidos de un archivo muy
 grande. Tambien se utiliza en conjuncion con otros comandos para poder ver la
 salida de los mismos pagina por pagina. Ejemplos:

  ==> more /var/log/dmseg

 Este comando nos muestra el contenido del archivo de "log" que se escribe
 al iniciarce el sistema y contiene los mensajes que el kernel emite al
 iniciarse.

  ==> ls -l | more

 Este es un comando tipico de los usuarios de Linux. Sirve para listar los
 contenidos de un directorio en formato largo, y poder ver el listado pagina
 por pagina. En este caso more se detendra cuando una pantalla se llene y
 esperara que apretemos "SPACE" para pasar a la siguiente pagina. Si apretamos
 "b" (back), volvemos a la pagina anterior y si orpimimos "q" (quit)
 interrupiremos inmediatamente la visualizacion.

 8.3 UTILIDADES PARA AGRUPAR Y COMPRIMIR ARCHIVOS

 8.3.1 gzip y bzip2: COMPRESION DE ARCHIVOS

 Hay dos utilidades de compresion sin perdida que comunmente son provistas
 con las distribuciones de Linux: gzip y bzip2. El primero utiliza el
 algoritmo de compresion "Lempel-Ziv" mientras que el segundo utiliza una
 tecnica llamada "ordenamiento de bloques". Existen otras utilidades de
 compresion como lo son pack y compress, pero hoy en dia son consideradas
 obsoletas y las dos primeras son las que mas se utilizan.

 El modo de uso es en ambas utilidades igual, por lo que ilustraremos con
 ejemplos indistintamente. Tambien haremos unas pruebas para mostra cual
 de las dos utilidades es mas eficiente.

 Estas utilidades reciben una lista de argumentos (que deben ser archivos)
 y comprimen cada uno de ellos sobreescribiendo los archivos originales y
 agregando como sufijo al nombre del archivo la extension gz. Veamos un
 ejemplo en la figura 8.8a.

  # ls -l
  -rw-r--r--   1 tony   users       7559 May 12 04:31 commands.htm
  -rw-r--r--   1 tony   users       3817 May 12 04:31 krabber-2.html
  -rw-r--r--   1 tony   users       2880 May 12 04:31 vi.htm
  # gzip commands.htm krabber-2.html vi htm
  # ls -l
  -rw-r--r--   1 tony   users       2050 May 12 04:31 commands.htm.gz
  -rw-r--r--   1 tony   users       1746 May 12 04:31 krabber-2.html.gz
  -rw-r--r--   1 tony   users       1102 May 12 04:31 vi.htm.gz
  # gzip -d *.gz
  # ls -l
  -rw-r--r--   1 tony   users       7559 May 12 04:31 commands.htm
  -rw-r--r--   1 tony   users       3817 May 12 04:31 krabber-2.html
  -rw-r--r--   1 tony   users       2880 May 12 04:31 vi.htm

            a. Utilizando gzip para comprimir varios archivos

  # ls -l netscape
  -r-xr-xr-x   1 root   root      12078064 Oct 13  1998 netscape
  # gzip netscape
  # ls -l netscape.gz
  -r-xr-xr-x   1 root   root       5138529 Oct 13  1998 netscape.gz
  # gzip -d netscape.gz
  # bzip2 netscape
  # ls -l netscape.bz2
  -r-xr-xr-x   1 root   root       4739906 Oct 13  1998 netscape.bz2
  # bzip2 -d netscape.bz2
  # ls -l netscape
  -r-xr-xr-x   1 root   root      12078064 Oct 13  1998 netscape

            b. Testeando al eficiencia de ambas utilidades.

         Figura 8.8: Utilizando gzip y bzip2 para comprimir archivos.

 Como vemos en el ejemplo, tanto gzip como bzip2 son invocados con la opcion
 -d (decompress) para descomprimir un archivo comprimido. Asi el archivo
 recupera su tamao y nombre original.

 En la figura 8.8b vemos una comparacion entre ambas utilidades de compresion.
 Se tomo el archivo ejecutable del Netscape Communicator 4.5 como objeto de
 prueba. El archivo, sin comprimir, ocupa exactamente 12078064 bytes. Al
 comprimir con gzip obtuvimos un archivo con un tamao de 5138529 bytes, lo
 que implica un grado de compresion del 57.4 %. Al comprimirlo con bzip2
 obtuvimos un archivo de 4739906 bytes lo que implica un grado de compresion
 del 60.76%. En este caso comprimio mejor bzip2. En general bzip2 realiza
 mejores compresiones que gzip pero con el costo de tardar un poco mas. Hoy,
 esta ganando terreno la utilizacion del bzip2.

 En el ejemplo anterior, vimos los grados de compresion que alcanzaron ambas
 utilizadades. Estos grados son muy buenos teniendo en cuenta que el archivo
 objeto de la prueba era un archivo binario. En general, se logran mejores
 compresiones sobre los archivos de texto, por ejemplo: fuentes de algun
 programa. Luego en la seccion que trata sobre la utilidad tar veremos un
 ejemplo de esto, comprimiendo las fuentes del kernel de Linux.

 8.3.2 tar: AGRUPAR ARCHIVOS

 Las utildades gzip y bzip2 son muy buenas comprimiendo grandes archivos, pero 
 no pueden hacer mucho sobre archivos pequeos. Primero, los archivos pequeos
 son pequeos, valga la redundancia, y comprimirlos no nos trae mucho
 beneficio. Pero el problema, es que existe una dificultad tecnica que tenemos
 que entender. En Linux, el espacio en disco es reservado de a bloques de 1
 Kilobyte, en los sistemas de archivos de otros Unix se reserva espacio en
 "clusteres" de 2, 4 o hasta 8 bloques de 512 bytes. Esto significa que si
 creamos un archivo que solo contiene un caracter, en Linux ocupara 1 Kilobyte
 y en otros Unix puede ocupar de 1 a 4 Kilobytes.

 La implicancia directa de esto es que no nos trae ningun beneficio comprimir
 un archivo de, por ejemplo 512 bytes ya que por mas que comprimido ocupe
 menos espacio, seguira almacenado en un bloque de 1 kilobyte.

 Otra dificultad con los archivos pequeos, es que, em general, se tiene
 muchisimos de ellos. Si tenemos unos pocos archivos de 1K no tendremos
 problemas, pero tener 5.000 o 10.000 archivos de ese tamao pueden hacernos
 perder espacio rapidamente.

 La utilidad tar soluciona esto y otros problemas. Esta utilidad fue
 originalmente desarrollada como un programa para escribir archivos de
 cintas magneticas, su nombre es "Tape archiver". Las cintas se tratan como
 un gran archivo secuencial y tar fue diseado para empaquetar conjuntos de
 archivos en un gran archivo para ser almacenado en cinta. Todavia se
 continua utilizando tar para realizar backups en cinta magnetica, pero
 tambien es muy util para archivar grandes conjuntos de archivos en un unico
 archivo llamado "tar-archive".

 Tar puede ahorrar espacio ya que almacena archivos en un gran archivo sin
 la limitacion de un tamao de cluster fijo. Los archivos se colocan uno
 despues del otro separados por un encabezado. Un grupo de archivos pequeos
 dentro de un tar-archive puede ser facilmente comprimido utilizando las
 utilidades gzip o bzip2.

 Los compresores se utilizan como complemento de la utilidad tar para
 comprimir un arbol de directorios recursivamente. Primero se agrupan todos
 los archivos y directorios a comprimir en un tar-archive y luego este es
 comprimido con la ayuda de un compresor, ya sea gzip o bzip2. En la figura
 8.9a vemos como se utiliza tar en conjunto con un compresor para crear un
 archivo comprimido que contenga toda la informacion del subdirectorio en
 cuestion, en este caso las fuentes del kernel de Linux, version 2.2.5.
 Elegimos las fuentes del kernel como archivo objeto porque son muchismos
 archivos de texto y con una estructura de directorios y subdirectorios
 muy compleja. Asi vemos que con un par de comandos almacenamos toda la
 estructura de subdirectorios en un unico archivo y luego lo comprimimos
 para que ocupe poco espacio.

  # du -hs linux-2.2.5
  51M linux-2.2.5
  # tar -c linux-2.2.5 | gzip > linux-2.2.5.tar.gz
  # du -hs linux-2.2.5.tar.gz
  13M linux-2.2.5.tar.gz

     a. Comprimiendo un arbol de directorios.

  # gzip -dc linux-2.2.5.tar.gz | tar -xf -
  # du -hs linux-2.2.5
  51M linux-2.2.5

     b. Descomprimiendo un arbol de directorios. 
 
   Figura 8.9: Comrpimiendo y descomprimiendo un arbol de directorios.

 El comando utilizado es tar -c ya que la opcion -c (create) hace que el
 comando tar cree un nuevo tar-archive y como no se especifica un archivo
 de salida (opcion -f nombre) tar envia la salida a la salida estandar. La
 caeria creada permite que el comando gzip obtenga la salida de tar y
 comprima enviando el resultado a la salida estandar la cual es redireccionada
 al archivo linux-2.2.5.tar.gz. Tambien vemos que el directorio, junto con
 todos sus subdirectorios y archivos ocupa 51 Megabytes. Una vez agrupado y
 comprimido el tamao del archivo es de solo 13 Megabytes, lo que implica un
 grado de compresion del 74.5%.

 En la figura 8.9b mostramos como se puede descomprimir el archivo
 linux-2.2.5.tar.gz.

 El comando es otra vez una caeria, pero esta vez en sentido inverso. Se
 utiliza el comando gzip con la opcion -d para que descomprima y la opcion -c
 para que envie el resultado a la salida estandar. Luego utilizamos el
 comando tar para desagrupar los archivos y necesitamos agregrales las
 opciones -x (extract) para que extraiga los archivos y -f para indicarle que
 es un tar-archive. Ademas debemos agregarle el simbolo "-" para indicarle
 que lea de la entrada estandar y asi pueda recibir la salida del compresor.
 Luego realizamos un chequeo y vemos que se encuentra el directorio
 linux-2.2.5 y que su tamao es nuevamente 51 Megabytes.

 8.4 UTILIDADES DE AYUDA

 8.4.1 man: INFORMACION DE LOS COMANDOS Y UTILIDADES

 Los sistemas de la familia Unix, tiene un sistema de ayuda "on-line" para
 los comandos y utilidades del sistema muy completo y practico que es llamado
 "Man-Pages" (manuales).

 La utilidad man es un programa que formatea (de darle forma) y visuliza los
 manuales de los comandos y utilidades del sistema.

 Esta utilidad se invoca con un argumento que debe ser un comando o utilidad
 valida del sistema o cualquier programa que hayamos instalado que posea
 manuales instalados. El siguiente comando nos mostrara el manual del
 comando ls.

  ==> man ls

 Dentro del entorno de la utilidad man hay varios comandos que es util
 conocer:

  1- Avanzar: Avanzamos por las paginas del manual utilizando la barra
              espaciadora o "space".

  2- Retrocerder: Retrocedemos una pagina del manual utilizando la tecla "b"
                  (back).

  3- Salir: Salimos del manual con la tecla "q" (quit).

 8.5 OTRAS UTILIDADES

 8.5.1 passwd: CAMBIANDO EL PASSWORD

 El comando passwd se utiliza para cambiar el "password" del usuario. Algunas
 personas cambian su password periodicamente para mantener la seguridad. El
 comando passwd primero nos obliga a ingresar el password actual y si es
 valido nos pregunta dos veces el nuevo password, para verificar que no nos
 hayamos equivocado. Ninguno de los passwords es mostrado en la pantalla por
 cuestiones de privacidad y seguridad.

 El superusuario (root) puede setear el password de cualquier usuario, pero
 los usuarios ordinarios solo pueden cambiar sus propios passwords.

 En algunos sistemas los passwords se "venden", es decir que duran un cierto
 tiempo. El sistema nos obligara a cambiar nuestro password la proxima vez
 que iniciemos una sesion pasado el periodo de vencimiento.


 CAPITULO 9

 INSTALACION DE SOFTWARE ADICIONAL

 Una vez instalado el sistema Linux, estamos en condiciones de utilizar una
 gran cantidad de utilidades y programas que vienen como parte del mismo. La
 gran mayoria del software que viene con las distribuciones de Linux, es
 actualizado permanentemente, ya sea porque se perfecciona o porque se le
 agregan nuevas caracteristicas. Ademas, hoy en Internet, podemos conseguir
 una infinidad de programas adicionales de distintas areas. Para poder
 instalar con exito cada uno de los programas que conseguimos es necesario
 que conozcamos algunos detalles importantes.

 Existen una gran cantidad de sitios en Internet, donde es posible conseguir
 las ultimas versiones de los programas y utilidades mas conocidas en el
 sistema Linux. En el apendice A se listan las direcciones de los sitios
 mas importantes, los que no tenemos que dejar de visitar.

 9.1 SOFTWARE DISTRIBUIDO CON CODIGO FUENTE

 El software para Linux o Unix, en general es distribuido con el codigo
 fuente, ya que existen una gran cantidad de plataformas Unix con distintas
 caracteristicas. Seria inviable que el autor del software compile y genere
 una version ejecutable binaria del programa para cada plataforma y la
 publique para que podamos disponer de ella. Para evitar esto, cada version
 de la familia Unix posee un sistema de compilacion y generacion de
 ejecutables como parte del sistema. Asi teniendo el codigo fuente del
 programa, podemos compilar y generar una version ejecutable del mismo, sobre
 nuestra plataforma y con todas las caracteristicas de nuestro sistema, de
 forma casi transparente. La obvia desventaja de esta aproximacion es el
 tiempo extra que tenemos que invertir compilando los programas, sobre
 todo si los mismos son muy grandes.

 El echo de contar con el codigo fuente de los programas (usualmente C, C++),
 nos da la posibilidad de poder modificar los mismos y adaptarlos a nuestras
 necesidades particulares. Asi podemos modificar el codigo fuente y volver a
 compilar el ejecutable, tantas veces como queramos.

 Una complicacion adicional surge al encontrarse con el codigo fuente de los
 programas: los mismos pueden necesitar utilizar librerias para poder
 compilarlos. La seccion 9.3 se ocupa de explicar como podemos instalar nuevas
 librerias en nuestro sistema.

 9.1.1 LA DISTRIBUCION

 La mayoria del software que podemos conseguir en Internet se encuentra
 agrupado y comprimido con los formatos tar y gzip o bzip2 respectivamente.

 Antes de realizar la instalacion es necesario descomprimir y desagrupar los
 contenidos. Vamos a ver un ejemplo con el programa cdda2wav que es una
 utilidad para copiar cd's de audio a formato de archivo de sonido de onda
 (wav). El archivo de la distribucion es cdda2wav-1.0c.tar.gz. El comando
 para descomprimir y desagrupar el contenido del archivo puede ser:

  ==> tar -zxvf cdda2wav-1.0c.tar.gz

   o el equivalente

  ==> gzip -dc cdda2wav-1.0c.tar.gz | tar -xvf -

    NOTA: Si el formato es .tar.bz2 no es posible utilizar la primera forma
          del comando. Es necesario invocar un comando de la forma del
          segundo, reemplazando el descompresor gzip por el bzip2.

 Luego de haber descomprimido y desagrupado las fuentes, en general,
 obtendremos un directorio con los contenidos del archivo. En la figura 9.1
 vemos el contenido del directorio obtenido.

  # cd cdda2wav-1.0c
  # ls
  Fronted               byteorder.h         md5c.h             scsilib
  GLP                   cdda2mp3            md5c.c             semshm.c
  HOWTOUSE              cdda2mp3.new        missing            semshm.h
  HPUX-Notes            cdd2wav.1           mkinstalldrs       setuid.c
  Makefile.am           cdd2wav.c           mycdrom.h          setuid.h
  Makefile.in           cdd2wav.h           mytype.h           sndconfig.c
  NEWS                  cdda_links          pitchplay          sndconfig.h
  OtherProgs            config.guess        raw.c              sun.c
  README                config.h            raw.h              sun.h
  README.2_0_33         config.sub          readmult           toc.c
  README.GoldstarR580B  configure           resample.c         toc.h
  README.INSTALL        configure.in        resample.h         tracknames.pl
  README.paranoia       global.h            ringbuff.c         tracknames.txt
  THANKS                install-sh          ringbuff.h         wav.c
  TODO                  interface.c         scan_scsi.linux    wav.h
  aclocal.m4            interface.h         scsi_cmds.c
  add_wav               lowlevel.h          scsi_cmds.h

     Figura 9.1: El contenido tipico de una distribucion de codigo fuente.

 Es usual que los desarrolladores del software agregen en la distribucion
 archivos INSTALL o README que son muy utiles al momento de compilar e
 instalar, ya que especifican las instrucciones de compilacion e instalacion
 que debemos seguir para poder instalar el programa con exito.

 A continuacion, vamos a explicar el proceso de compilacion e instalacion mas
 comunmente utilizados. ES NECESARIO ACLARAR QUE NO TODO EL SOFTWARE QUE
 PODEMOS CONSEGUIR SIGUE ESTAS CARCTERISTICAS. SIEMPRE DEBEMOS REMITIRNOS,
 COMO PRIMER MEDIDA, A LAS INSTRUCCIONES RESPECTIVAS DE CADA PROGRAMA.

 9.1.2 LA CONFIGURACION

 Como paso previo a la compilacion, debemos iniciar un proceso de
 configuracion del software. El mismo escaneara nuestro sistema en busca de
 los requerimientos del programa para ver si los mismos se encuentran
 instalados o no, y para determinar otros parametros necesarios a la hora de
 compilar.

 Para iniciar este proceso de configuracion, debemos ejecutar el comando:

  ==> ./configure

 Dentro del directorio del programa. Seguiran una serie de mensajes de
 estado y configuracion, los cuales terminaran en la generacion de los
 archivos Makefile que son requisitos imprescindibles a la hora de compilar.
 La salida de esta etapa son estos archivos que contienen las instrucciones
 para que el compilador pueda trabajar.

   NOTA: Si en esta etapa el proceso de configuracion se detiene con un
         mensaje de error, es posible que nos este faltando una libreria o
         algo necesario para la configuracion del programa. Anotar
         precisamente el error y luego referirse a los archivos INSTALL o
         README respectivos a cada programa con el fin de determinar la causa
         del error.

 9.1.3 LA COMPILACION

 La compilacion es el proceso por el cual el texto fuente de un programa es
 traducido al formato binario (leguaje entendido por la maquina) para que la
 misma este en condiciones de ejecutarlo. Es una tarea automatica (por lo
 menos desde el punto de vista del usuario). En general, ejecutando el
 comando

   ==> make

 (construir) daremos comienzo a la tarea de compilar el programa. Este comando
 indica al compilador que comience su tarea, y el mismo, en base a las
 instrucciones de los archivos Makefile generados en la etapa anterior, ira
 construyendo los distintos componentes del programa, para finalizar su tarea,
 vinculando los componentes generados en uno o mas ejecutables que forman
 parte del programa. Estos ejecutables seran guardados en el directorio donde
 tenemos el codigo fuente del programa. Como paso restante, queda instalar los
 ejecutables y documentacion (usualmente provista con el codigo fuente - no
 es necesario compilar) en el directorio correspondiente, para asi poder
 comenzar a utilizar el programa en nuestro sistema.

 9.1.4 EL DIRECTORIO /usr/local

 El directorio /usr/local usualmente es el lugar en la jerarquia de archivos
 donde se instala el software adicional, es decir aquel software que no haya
 sido provisto inicialmente con la distribucion del S.O. Linux instalada.

 La mayoria del software posee como destino de instalacion predeterminado
 este directorio, por lo que el programa se instalara en ese lugar. Este
 directorio posee una serie de subdirectorios que lo forman, los mismos son
 (lista no exhaustiva):

  * /usr/local/bin: Es el directorio donde se guardan los ejecutables.

  * /usr/local/lib: Es el directorio donde se instalan las librerias.

  * /usr/local/man: Es el directorio donde los programas instalan sus
                    man-pages.

  * /usr/local/doc: Es el directorio donde se almacena la documentacion
                    adicional. Usualmente paginas Html.

  * /usr/local/include: Es el directorio donde se guardan los encabezados
                        de las librerias. Este directorio es escaneado por
                        los programas de configuracion, para ver si se
                        ecuentran disponibles ciertas librerias.

  * /usr/local/games: En este directorio se instalan los programas de
                      entretenimiento.

  * /usr/local/share: Este directorio es tomado como directorio destino de
                      ciertos programas que tienen informacion extra y la
                      necesitan para poder trabajar.

 Adicionalmente, hay programas que son muy grandes que reservan un directorio
 para ellos con su nombre dentro del directorio /usr/local. Por ejemplo:
 Netscape Communicator /usr/local/netscape, KDE (Kommon Desktop Environment)
 /usr/local/kde.

 9.1.5 LA INSTALACION

 El ultimo paso a realizar es la instalacion. Para ello ejecutamos el
 siguiente comando:

  ==> make install

 Este comando iniciara un proceso de instalacion que se ocupa de copiar todos
 los archivos necesarios a el/los directorios destino especificados. Seguiran
 una serie de mensajes y luego se dara por finalizada la instalacion.

   NOTA: Es necesario estar en una sesion con permisos de superusuario para
         poder ejecutar este comando, ya que si no tenemos permiso de
         escritura en el directorio destino, el proceso de instalacion
         abortara con un error. Para esto, podemos iniciar una sesion con el
         usuario root, o ejecutar directamente el comando su (superuser), el
         cual nos pedira la contrasea del superusuario y si es correcta,
         iniciaremos una sesion con permisos de superusuario. Una vez
         finalizada la instalacion, podemos retornar a la sesion anterior con
         el comando exit.

 Es posible que cada programa necesite que realicemos ciertas configuraciones
 adicionales para hacer que el programa funcione. Usualmente debemos seguir
 una serie de instrucciones que son especificadas en la documentacion del
 programa. Las configuraciones tipicas que debemos realizar son edicion del
 camino de busqueda, creacion y exportacion de variables de entorno, etc.
 Todos estos temas seran tratados en capitulos posteriores.

 9.2 EL SISTEMA DE PAQUETES RPM

 RPM (RedHat Package Manager) es un sistema de manejo de paquetes de software
 muy potente, que puede ser utilizado para construir, instalar, consultar,
 verificar, actualizar y desinstalar paquetes de software individuales. Un
 paquete consiste de dos partes fundamentales: el software en si y un
 encabezamiento que contiene la informacion del paquete (nombre, version,
 dependencias, etc).

 RPM le otorga al administrador al habilidad de poder actualizar componentes
 individuales o sistemas enteros conservando la configuracion del sistema o
 paquete, consultar la base de datos de paquetes para averiguar la locacion
 de los archivos, paquetes o informacion relacionada.

 RPM es el sistema de manejo de paquetes de Red Hat, pero esto no significa
 que solo pueda ser usado en una distribucion Red Hat. Se desarrollo pensando
 en ser un sistema de paquetes abiertos, es decir, para poder ser utilizado
 en cualquier distribucion. Actualmente, Red Hat recomienda a otros
 distribuidores de Linux a usarlo en sus distribuciones. Hoy, podemos
 considerar que es el sistema de manejo de paquetes mas utilizado en la
 comunidad Linux.

 9.2.1 CONVENCIONES EN LOS NOMBRES DE LOS PAQUETES

 Un paquete de software RPM construido correctamente tiene la caracteristica
 de que su nombre (package.rpm) identifica la siguiente informacion: el nombre
 del paquete, su version, la ultima revision de compilacion y la arquitectura
 para la cual fue construido. En general los paquetes son distribuidos en
 archivos con extension .rpm.

 Veamos un ejemplo con el paquete XFree86-3.3.1-14.i386.rpm. El nombre del
 paquete es XFree86 y es el sistema grafico de ventanas que se utiliza en
 Linux. Su version es la 3.3.1 y es revision 14 de esa version. La plataforma
 para la cual fue construido es la Intel 80386 o superiores. Como vemos, el
 nombre del archivo mediante el cual se distribuye el paquete nos puede
 brindar mucha informacion del mismo.

 Es mas, aun, la informacion que posee un paquete internamente. Aunque el
 estudio de la estructura interna de un paquete RPM esta, claramente, fuera
 del ambito de este manual, podemos destacar que en un paquete internamente
 tiene:

  * Archivos ejecutables.
  * Archivos de configuracion.
  * Archivos de documentacion (HTML, man-pages, etc).
  * Archivos miscelaneos relacionados directamente con el paquete.
  * Un registro de los lugares donde se deben instalar los archivos.
  * Un registro de todos los paquetes requeridos (dependencias).

 9.2.2 LA BASE DE DATOS DE RPM.

 El sistema de manejo de paquetes RPM mantiene una base de datos, local al
 sistema, donde se mantienen los datos de todos los paquetes instalados en el
 sistema.

 Una vez instalado un paquete exitosamente, toda la informacion del paquete
 se registra en la base de datos.

 9.2.3 MODOS DE OPERACION DE RPM

 Todas las operaciones del sistema de manejo de paquetes se realizan con el
 programa rpm. El mismo tiene varios modos de operacion, donde cada uno de
 ellos posee opciones especiales.

  NOTA: Sobre el sistema de ventanas X-Windows existen varias herramientas
        graficas de manejo de paquetes, que son muy faciles de utilizar y
        muy comodas. Algunas de ellas son: kpackage (para el Windows Manager
        KDE), X Package Management Tool (es provisto con las herramientas
        estandar de la distribucion Red Hat).

 Los 4 modos mas importantes de la operacion son:

 Modo de Instalacion:

  ==> rpm -i [install-options] <package>

  Este comando instala un nuevo paquete. El siguiente comando actualiza un
  paquete de version mas nueva que la anterior.

  ==> rpm -U [install-options] <package>

  Las opciones de instalacion mas importantes son:

   * --replacefiles: reemplaza todos los archivos, por mas que sean de otros
                     paquetes.

   * --allfiles: instala o actualiza todos los archivos, por mas que no
                 exista.

   * --nodeps: no realiza un chequeo de dependencias sobre el paquete a
               instalar.

 Modo de consulta:

 La forma general de un comando de consulta es:

  ==> rpm -q [query-options]

  Las opciones de consulta mas importantes son:

  * <package-name>: consulta el paquete con ese nombre. Notar que no es el
                    nombre del archivos, sino el nombre del paquete.

  * -a: consulta todos los paquetes.

  * -l: lista los archivos que contiene un paquete.

  * -R: lista las dependencias del paquete.

  * -p <package-file>: consulta un archivo .rpm que no esta instalado.

  * -i: muestra la informacion del paquete: nombre, version, etc.

 Modo de verificacion:

 El modo de verificacion nos permite comparar la informacion de los archivos
 instalados como parte de un paquete con la informacion de los archivos
 sacada del paquete original que es guardada en la base de datos de RPM.
 Incluyendo otras cosas, el modo de verificacion, compara el tamao de los
 archivos, permisos, tipos, dueos y grupos de cada archivo. Cualquier
 discrepancia se muestra en pantalla. 

 El comando de verificacion es de la siguiente forma:

  ==> rpm -V [verify-options]

  Las opciones de especificacion de paquetes son iguales a las de consulta.

 Modo desinstalacion

 La forma del comando de desisnstalacion es la siguiente:

  ==> rpm -e <package-name>

  Pueden ser especificadas opciones adicionales:

  * --nodeps: no realizar un chequeo de las dependencias. Si algun paquete
              instalado necesita del paquete que estamos desinstalando, se
              borrara igual.

  * --allmatches: remueve todas las versiones del paquete especificado.

 9.3 UTILIACION DE LIBRERIAS

 Con el objetivo de hacer que los programas sean mas pequeos, los mismos se
 desarrollan utilizando el concepto de "librerias compartidas". Las librerias
 son colecciones de modulos ya desarrollados, para ser utilizados en el
 desarrollo de nuevos programas. Estas colecciones, de alguna forma, son
 factorizadas, es decir se proveen una sola vez y cualquier numero de
 programas pueden utilizar su funcionalidad.

  NOTA: O sea, que si tenemos muchos programas que utilizan un mismo archivo
        en comun para funcionar, no es necesario que haya una copia del
        mismo para cada programa que lo utilice. Sino que que todos los
        programas que utilicen ese archivo pueden usar un solo archivo que
        se comparte con el resto de los programas que lo utilicen tambien.

 En el S.O. Linux, el concepto de librerias compartidas es muy utilizado por
 los programadores a la hora de desarrollar el software. A la hora de instalar
 un nuevo programa, podemos encontrarnos con la necesidad de instalar
 previamente algun conjunto de librerias. Primero veremos cuales son los
 lugares donde se encuentran las librerias en nuestro sistema y luego veremos
 como se pueden instalar librerias adicionales.

 9.3.1 DIRECTORIOS DE LAS LIBRERIAS

 Las librerias, en el S.O. Linux, se encuentran distribuidas en varios
 lugares. A diferencia de otros S.O., que mantiene todas las librerias en
 un lugar centralizado (con las desventajas que esto trae), Linux las
 distribuye de acuerdo a unas convenciones muy simples. Los directorios
 comunmente utilizados son los siguientes:

  /lib: Son las librerias necesarias para poder ejecutar los programas que
        se encuentran en los directorios /bin y /sbin.

  /usr/lib: Son las librerias que necesitamos para poder ejecutar los
            programas que se encuentran en /usr/bin y /usr/sbin.

  /usr/X11R6/lib o /usr/X11/lib: Son librerias que utiliza el sistema de
                                 ventanas X-Windows y los programas que
                                 funcionan con el mismo. Usualmente son
                                 librerias graficas.

  /usr/local/lib: Este es el directorio que usamos comunmente para instalar
                  las librerias adicionales que nosotros instalamos como
                  parte de algun programa.

 9.3.2 INSTALACION DE LIBRERIAS

 Las librerias en Linux, en general, son provistas con su codigo fuente, por
 las mismas razones que el software es distribuido asi.

 El proceso necesario para instalar una determinada libreria puede variar
 considerablemente. Hoy, la tendencia es a seguir el mismo procedimiento
 que con el software. Es decir que tenemos que seguir los mismos pasos de
 "configuracion", "compilacion" e "instalacion" descriptos en la seccion 9.1. 
 Si la libreria, necesita que sigamos algun otro proceso de instalacion,
 deberemos referirnos a su documentacion y seguir las instrucciones de
 instalacion que usualmente son provistas como parte de la distribucion del
 software.

 Una vez realizada la instalacion de la libreria, nos resta realizar un paso
 adicional para que puedan ser utilizadas en el sistema. El S.O. mantiene un
 "vinculador de tiempo de ejecucion (run time linker)" que mantiene una base
 de datos de las librerias disponibles para los programas. Cuando un programa
 necesita utilizar una libreria, entra en juego este vinculador y realiza la
 "vinculacion" entre el mismo y la libreria, para que el primero la pueda
 utilizar. Cuando agregamos una libreria al sistema, debemos asegurarnos que
 el vinculador se "entere de su existencia".

 EL ARCHIVO /etc/ld.so.conf

 Este archivo mantiene una lista de los directorios donde tenemos librerias
 instaladas en el sistema. El contenido de un archivo de estos es mostrado
 en la figura 9.2.

  # cat /etc/ld.so.conf
  /usr/i486-linux-libc5/lib
  /usr/X11R6/lib
  /usr/local/lib
  /usr/local/kde/lib

          Figura 9.2: Un archivo /etc/ld.so.conf.

 Este archivo mantiene los directorios que son escaneados por el vinculador
 de tiempo de ejecucion en busca de librerias instaladas en el sistema.
 Normalmente, el vinculador esta configurado para actualizar la informacion
 de las librerias cada vez que se inicia el sistema. Por lo tanto, se puede
 pensar que para que el vinculador encuentre nuestra libreria, solo es
 necesario agregar el directorio donde se instalo la misma y luego reiniciar
 el sistema. Ese razonamiento no es erroneo, pero no es muy practico que
 digamos.

 Linux es un sistema que esta diseado para evitar ser reiniciado, salvo
 situaciones extremas, a diferencia de otros S.O. que necesitan ser
 reiniciados por cosas minusculas. Es inaceptable tener que reiniciar el
 sistema porque se agrego una libreria al sistema, sobre todo teniendo en
 cuenta que Linux es "multiusuario" y si tenemos usuarios conectados
 tendremos que desconectarlos del sistema para poder reiniciar, o sin ir
 mas lejos pensemos en un sistema que actua como servidor de WWW y que esta
 atendiendo pedidos y se lo reinicia sin previo aviso.

 Para evitar reiniciar el sistema cada vez que instalamos un nuevo programa
 o libreria, Linux posee un comando que le indica al vinculador de tiempo de
 ejecucion que refresque la informacion de las librerias escaneando los
 directorios nuevamente. Una vez que hayamos editado el archivo
 /etc/ld.so.conf, debemos ejecutar el siguiente comando:

  ==> ldconfig

 el mismo refrescara las librerias que el vinculador considerara de ahi en
 adelante. A partir de eso podemos comenzar a utilizar el programa ya que el
 vinculador encontrara al libreria en el momento que el programa la solicite.

 Tanto la ejecucion de este comando como la edicion del archivo
 /etc/ld.so.conf se deben hacer con privilegios de superusuario ya que un
 usuario ordinario NO DEBE TENER PERMISO para escribir el archivo
 /etc/ld.so.conf y el comando ldconfig usualmente no se encuentra disponible
 para ser ejecutado por un usuario comun.


 CAPITULO 10

 MONTANDO SISTEMAS DE ARCHIVOS

 Como vimos en capitulos anteriores, todos los archivos en un sistema Linux
 se acomodan en un gran arbol: la jerarquia de archivos tiene a "/" como
 raiz. Estos archivos pueden estar distribuidos en distintos dispositivos

 Antes de poder utilizar un sistema de archivos, debemos "montarlo" sobre
 la jerarquia de archivos. Para ello necesitaremos conocer el dispositivo a
 montar y tener disponible un punto de montaje (un directorio). El comando
 mount nos sirve para agregar un sistema de archivos a la jerarquia de
 archivos. De forma opuesta, el comando unmount, eliminara la asociacion
 creada con el comando mount.

 10.1 SISTEMAS DE ARCHIVOS Y PARTICIONES

 Un sistema de archivos es una coleccion de archivos o directorios en algun
 dispositivo, con algun tipo o formato de almacenamiento. Discos de poca
 capacidad (por ejemplo: discos flexibles) solo poseen un sistema de archivos, 
 en cambio los discos grandes pueden tener varias regiones (particiones),
 cada una con su sistema de archivos propio.

 Existen varias motivaciones por las cuales se trata de particionar los
 discos. En el comienzo de Unix, particionar los discos era necesario porque
 las estructuras del kernel para mantener los datos de los archivos y
 sistemas de archivos no podian direccionar todo el espacio de almacenamiento
 disponible. En los sistemas Unix modernos (incluyendo a Linux) un archivo,
 potencialmente, puede tener como maximo 2 Gigabytes y un sistema de archivos
 puede ser tan largo como un Terabyte (1.000.000 Megabytes). Ningun disco,
 hoy, puede alcanzar esas capacidades, por lo que la decision de particionar
 el disco es opcional.

 Una de las razones por las cuales es adecuado particionar es la modularidad.
 Las particiones nos permiten controlar la cantidad de espacio que asignamos
 a una dada actividad o tipo de uso de un sistema de archivos: es usual
 crear una particion aparte para el directorio /tmp otra para el directorio
 /home donde se encuentran los datos de los usuarios, etc. Las particiones
 nos otorgan la posibilidad de realizar un control mas fino sobre las tareas
 de backup. Los archivos de solo-lectura y los temporales en general no se
 tienen en cuenta al realizar un backup. Manteniendolos en particiones
 separadas solucionamos este problema, ya que la tarea de backup toma todo o
 nada de la informacion de una particion.

 Un caso particular de particionamiento del disco disco lo encontramos en la
 particion utilizada para realizar el intercambio de datos cuando no queda
 memoria disponible (swap). Linux trata el espacio swap como una particion
 separada del sistema de archivos principal. La particion de swap esta
 organizada de forma contigua para poder ser accedida eficientemente, por lo
 que requiere una estructura distinta a la utilizada en el sistema de archivos
 principal. Esta es la causa por la cual el espacio de intercambio se mantiene
 en una particion especial.
 
 10.2 SINTAXIS DEL COMANDO MOUNT

 La forma estandar del comando mount es la siguiente:

  ==> mount -t type device dir

 Un comando de este tipo le comunica al kernel que monte el sistema de
 archivos de tipo "type" que se encuentra en el dispositivo "device" sobre
 el directorio "dir". Los contenidos del directorio "dir" (si existen) se
 vuelven invisibles, mientras el sistema de archivos se mantenga montado.

 La mayoria de los dispositivos se indican por un nombre de archivo, por
 ejemplo: /dev/hdb (la unidad IDE esclava-primaria), /dev/hda1 (la primera
 particion de la unidad de disco IDE master-primaria), /dev/cdrom (la unidad
 CD-ROM) o /dev/fd0 (la primera unidad de disco flexibles del sistema).

 Los programas mount y unmount mantienen una lista de los sistemas de archivos
 actualmente montados en el archivo /etc/mtab. Si se ejecuta el comando mount
 sin argumentos, la informacion contenida en ese archivo es mostrada como
 salida.

 10.3 MONTANDO SISTEMAS DE ARCHIVOS

 Para poder montar distintos sistemas de archivos debemos conocer: el
 dispositivo donde se encuentra el sistema de archivos, el tipo del sistema
 de archivos y el punto de montaje. Ademas de esto debemos tener los
 permisos de superusuario o tener permiso de montaje de usuario ordinario
 (esto se explica en la seccion 10.5.3).

 Una vez que conocemos toda esa informacion podemos utilizar el comando mount
 para montar el sistema de archivos en la jerarquia. Un tema muy delicado es
 el de los tipos de sistemas de archivos, ya que existen una gran variedad
 de sistemas de archivos, cada uno con su formato propio. Linux es capaz de
 manipular una gran cantidad de sistemas de archivos eficientemente, pero
 un item que usualmente confunde a los usuarios es el hecho de que para poder
 montar sistemas de archivos de un determinado tipo es necesario tener
 compilado el kernel con el soporte para ese tipo de sistema de archivos. En
 un capitulo posterior veremos como hacer para agregar al kernel el soporte
 para distintos sistemas de archivos. Por ahora supondremos que el kernel
 es capaz de entender cualquier sistema de archivos disponible.

 10.3.1 TIPOS DE SISTEMAS DE ARCHIVOS

 SISTEMAS DE ARCHIVOS FAT

 Si queremos accedera a archivos de particiones que contienen sistemas de
 archivos basados en FAT, debemos utilizar el tipo "msdos". En este caso los
 nombres de los archivos repetaran el formato de MS-DOS (windows 3.x), o sea
 nombres de 8 caracteres con extension de 3.

 Podemos utilizar el tipo "vfat" para montar sistemas de archivos de Windows
 95/98. Los kernels de versiones 2.0.x no soportan las extensiones de
 Microsoft para nombres largos, por lo que veremos los archivos con el formato
 de nombres de MS-DOS. A estos kernels es posible aplicarles un patch,
 disponible gratuitamente en Internet, para poder ver los nombres largos. Por
 suerte los kernels 2.2.x ya tiene ese soporte integrado por lo que no
 debemos realizar ninguna tarea adicional.

 El siguiente comando montara el sistema de archivos de Windows 95 que se
 encuentra en la particion 2 del primer disco de la maquina, en el directorio
 /mnt/win95.

  ==> mount -t vfat /dev/hda2 /mnt/win95

 Es posible montar discos flexibles de cualquiera de estos dos tipos. En
 general el dispositivo de la disquetera es /dev/fd0 o /dev/floppy. El
 siguiente comando nos muestra como podemos montar un diskette MS-DOS.

  ==> mount -t msdos /dev/fd0 /mnt/floppy

 SISTEMAS DE ARCHIVOS NTFS

 Anteriormente, dijimos que un sistema Linux puede coexistir con Windows NT
 en una maquina. Aicionalmente, podemos montar un sistema de archivos NTFS
 (el sistema de archivos de Windows NT) como parte de nuestra jerarquia. Para
 ello podemos utilizar el siguiente comando:

  ==> mount -t ntfs /dev/hda1 /nt

  NOTA: El soporte de NTFS del kernel (2.2.5) permite leer corectamente
        informacion, pero el soporte para escritura se encuentra en una etapa
        experimental y es muy peligroso activarlo, ya que podemos romper la
        estructura del sistema de archivos NTFS y volverlo inutilizable.
        Se recomienda montar estos sistemas de archivos como solo lectura.

 MONTANDO CD-ROM'S (SISTEMA DE ARCHIVOS ISO9600)

 El sistema de archivos estandar utilizado en los cd-rom que contiene datos
 es el ISO9600, conocido previamente como "High Sierra Filesystem" (hsfs),
 por lo que en otros Unix es conocido de tal forma.

 Como el medio de almacenamiento de cd-rom es inherentemente de solo lectura,
 los cd-rom seran siempre montados como solo lectura.
 El comando para montar un cd-rom puede ser:

  ==> mount -t iso9600 /dev/cdrom /mnt/cdrom

 10.4 DESMONTANDO SISTEMAS DE ARCHIVOS

 Una vez que trabajamos con el sistema de archivos y ya no lo necesitamos
 podemos desmontarlo. Hay sistemas de archivos que se montan automaticamente
 al iniciarse y permanecen montados hasta que el sistema se baja. Mas adelante
 veremos como se pueden configurar los sistemas de archivos para que se
 comporten de esta manera.

 Los medios removibles (discos flexibles, cd-rom's, etc) y en ocasiones
 discos y particiones son montados temporariamente para leer o escribir
 informacion y luego son desmontados.

 El comando umount (unmount) nos permite desmontar un sistema de archivos.
 La informacion necesaria para desmontar un sistema de archivos puede ser el
 dispositivo o alternativamente el directorio donde esta montado. Por lo
 tanto podemos desmontar el cd-rom que montamos en la seccion anterior con
 cualquiera de los siguientes comandos:

  ==> umount /dev/cdrom

  ==> umount /mnt/cdrom

  Observaciones:

  * Un sistema de archivos no puede ser desmontado si se encuentra "ocupado",
    esto es, por ejemplo, cuando existen archivos del mismo que se encuentran
    abiertos o cuando algun proceso tiene como directorio de trabajo algun
    directorio del sistema de archivos. El comando fuser nos sirve para
    averiguar que usuarios, y que procesos, estan utilizando un determinado
    archivo o sistema de archivos. Adicionalmente nos permite matar estos
    procesos, para poder desmontar el sistema de archivos.

  * Cuando un sistema de archivos se encuentra montado, cierta informacion
    vital de la locacion de los archivos en ese sistema de archivos, se
    mantiene en memoria con el kernel. Si removemos el medio fisico sin
    realizar el umount puede suceder que la informacion que se encuentra en
    memoria se pierda, y el estado del sistema de archivos quede
    inconsistente. El proposito de la operacion umount es volcar toda la
    informacion del sistema de archivos, que se encuentra en memoria, al
    medio fisico, para que todo quede en un estado consistente.

 10.5 EL ARCHIVO /etc/fstab

 El archivo /etc/fstab (file system table) es uno de los archivos mas
 importantes en lo que concierne a la administracion del sistema. El mismo
 contiene lineas describiendo que dispositivos son usualmente montados, con
 que opciones y donde se montan los mismos. Contiene, ademas, la informacion
 de los sistemas de archivos que deben ser montados automaticamente al
 iniciarse el sistema.

 Es tarea del adminsitrador del sistema editar y mantener este archivo. Cada
 sistema de archivos se escribe en una linea separada. Cada linea contiene
 varios campos y estos son separados por tabs o espacios. Como ejemplo, vemos
 un archivo fstab en la figura 10.1.

  # Device or NFS         Mount Point            Type     Options

  /dev/hda3               /                      ext2     defaults             1 1
  /dev/hda2               /mnt/win95             vfat     defaults             0 0
  /dev/hda4               swap                   swap     defaults             0 0
  /dev/fd0                /mnt/floppy            vfat     user,noauto          0 0
  /dev/hdb                /mnt/cdrom             iso9600  ro,user,noauto,noide 0 0
  none                    /proc                  proc     defaults             0 0
  /dev/hda1               /mnt/nt                ntfs     unmask=022,ro        0 0

           Figura 10.1: Un archivo /etc/fstab con informacion de los
                        sistemas de archivos.

 10.5.1 CAMPOS DE CADA ENTRADA

 Device or NFS: Especifica el dispositivo donde se encuentra el sistema de
                archivos. En caso de ser un sistema de archivos en red (NFS),
                no se especifica un dispositivo, sino que debemos poner el
                nombre del host, del directorio que se encuentra compartido.

 Mount Point: Punto de montaje. Es el directorio que forma parte de la
              jerarquia, donde queremos montar el sistema de archivos.
              Notemos que estos directorios solo pueden ser especificados
              con rutas absolutas. En caso de ser una particion swap, el
              punto de montaje es nulo y se especifica con swap o none.

 Type: Es el tipo de sistema de archivos que se encuentra en el dispositivo.
       Puede ser: msdos, vfat, ext2, minix, iso9600, swap, etc. El kernel
       debe tener compilado el soporte para cada sistema de archivos que
       especificamos.

 Options: Este campo es una serie de opciones separadas por comas. Cada
          opcion tiene un comportamiento determinado y las opciones varian
          de acuerdo al tipo de sistema de archivos. Explicaremos las mas
          comunmente utilizadas:

          rw,ro: La primera (read/write) monta el sistema de archivos en
                  modo lectura/escritura. La segunda ro (read-only)
                  especifica que se montara como solo lectura.

          auto,noauto: Especifican si el sistema de archivos se montara al
                       iniciar el sistema o no.

          user,nouser: Especifican si el sistema de archivos puede ser
                       montado por el usuario ordinario o no.

          defaults: Especificamos que tome las opciones predeterminadas,
                    entre otras: rw,auto,nouser.

 10.5.2 USO DEL ARCHIVO FSTAB

 Este archivo, usualmente es utilizado en tres formas:

  1- El comando mount -a (all), usualmente ejecutado en los scripts de
     inicio del sistema, monta todos los sistemas de archivos especificados
     en el archivo /etc/fstab, salvo las que tengan la opcion noauto. En
     general los medios removibles (discos flexibles, cd-rom's, discos ZIP,
     etc.) son especificados con la opcion noauto.

  2- Cuando montamos un sistema de archivos que se encuantra especificado
     en el archivo /etc/fstab, basta con especificar el dispositivo a
     montar o el punto de montaje. El comando mount buscara el resto de la
     informacion en el archivo. Por ejemplo, suponiendo que nuestro archivo
     fstab es el de la figura 10.1 y queremos montar el cd-rom, podemos
     ingresar cualquiera de los siguientes comandos:

      ==> mount /dev/cdrom

      ==> mount /mnt/cdrom

  3- Para definir que sistema de archivos pueden ser montados por usuarios
     ordinarios. Ver seccion siguiente.

 10.5.3 PERMITIENDO MONTAR SISTEMAS DE ARCHIVOS A UN USUARIO ORDINARIO

 El comando mount debe ser utilizado solo por el administrador del sistema
 (root). Asi podemos tener seguridad en el sistema. No queremos que los
 usuarios ordinarios puedan montar y desmontar a gusto nuestros sistemas de
 archivos, pero seria una restriccion muy grande que los usuarios comunes
 no puedan montar, por ejemplo, un diskette. Para solucionar esto, sin
 comprometer la seguridad del sistema, el adminstrador especifica en el
 archivo /etc/fstab cuales son los sistemas de archivos que un usuario
 puede montar, utilizando la opcion user. El usuario puede, luego, montar el
 sistema de archivos, pero limitado al tipo, punto de montaje y opciones
 especificadas por el adminstrador en el archivo /etc/fstab.
 

 CAPITULO 11

 EL KERNEL Y LOS MODULOS

 11.1 QUE ES EL KERNEL?

 El kernel es el organizador principal del S.O. Linux. El kernel planifica
 la ejecucion de los procesos y se asegura de que cada uno de ellos obtenga
 una tajada "justa" de tiempo de procesador; realiza todo el manejo de
 memoria necesario para que los procesos puedan trabajar; provee una
 interfaz agradable y portable para que los procesos y programas de usuario
 puedan interactuar con el hardware; maneja todo lo respectivo a
 almacenamiento de datos en discos; realiza la supervision de las
 transmisiones de datos entre la memoria y los dispositivos perifericos y
 debe servir todos los pedidos de acceso a hardware de los procesos.

 El kernel es la porcion del S.O. Linux que se encuentra residente en memoria.
 Comparado a muchos S.O. de "mainframes", el kernel de Linux provee una
 funcionalidad relativamente pequea (aunque aumentando dia a dia). De todas
 formas, comparado a otros S.O. de microcomputadoras, como lo puede ser
 MS-DOS, Windows 95, etc., el kernel de Linux tiene un gran repertorio de
 servicios.

 El kernel nunca realiza alguna tarea directamente para el usuario; los
 servicios basicos del kernel son provistos mediante utilidades que
 establecen la interfase entre el usuario y el kernel.

 El kernel de Linux se ocupa, principalmente, de las siguientes tareas:

  Manejo de memoria: El subsistema de manejo de memoria es una de las partes
                     mas importantes del S.O. Desde los primeros dias de la
                     computacion, ha habido una necesidad de tener mas
                     memoria de la disponible fisicamente en un sistema. Se
                     han desarrollado varias estrategias para sobrepasar
                     esta limitacion, y la mas exitosa de todas, sin dudas,
                     ha sido la memoria virtual. La memoria virtual hace
                     parecer que el sistema tiene mas memoria que la fisica
                     usando almacenamiento en disco para ampliar la misma.
                     La ventaja de esto es que podemos ejecutar mas procesos
                     que los que quepan en memoria en un instante dado de
                     manera muy eficeinte.

  Procesos: Un proceso es un programa de computadora en accion, una entidad
            dinamica, su estado cambia constantemente a medida que es
            ejecutado. El kernel tiene la responsabilidad de comenzar los
            procesos, planificar su ejecucion de manera justa, enviarlos a
            espacio de intercambio (swap) cuando no hay mas memoria
            disponible y traerlos nuevamente a memoria cuando se libere
            espacio para que puedan seguir ejecutandose, otorgarles recursos
            y servir sus pedidos de interaccion con los dispositivos.

  Mecanismo de intercomunicacion entre procesos: Los procesos se comunican
      entre si y con el kernel para coordinar y sincronizar sus actividades.
      Linux soporta un numero de Mecanismos de Comunicacion entre Procesos
      (Inter-Process Communications - IPC), las seales y las caerias son
      dos de ellos. A su vez. Linux posee otro mecanismo muy potente de
      comunicacion entre procesos que son los sockets, este mecanismo es
      muy importante para la implementacion de los protocolos de red
      utilizados en varios sistemas. Adicionalmente, se tiene colas de
      mensajes, semaforos y memoria compartida.

  Manejadores de dispositivos (device drivers): Uno de los objetos
      principales de un S.O. es ocultar a los usuarios las peculiaridades
      especificas del hardware sobre el cual se ejecuta. El CPU (Central
      Processing Unit) no es el unico dispositivo de hardware "inteligente"
      en una computadora. Cada dispositivo posee su controladora en hardware
      que conoce perfectamente las caracteristicas del mismo y puede manejar
      su operacion satisfactoriamente. El software que maneja y controla una
      controladora de hardware se conoce como manejador de dispositivo
      (device driver). El kernel de Linux posee una gran cantidad de
      manejadores de dsipositivos y les encarga a ellos el tratamiento de
      bajo nivel de los dispositivos, pero siempre supervisando su tarea.

  Sistemas de archivos: La habilidad de manejar los sistemas de archivos en
      necesaria para poder almacenar y recuperar informacion de los medios
      de almacenamiento. En el pasado, cada sistema manejaba su propio
      sistema de archivos. Una de las potencialidades de Linux es el soporte
      que tiene para una gran variedad de sistemas de archivos distintos.
      Esta caracteristica hace de Linux un sistema altamente flexible y hace
      posible que coexista con otros S.O.

  Redes: El trabajo en red y Linux son casi sinonimos. En sentido real, Linux
         es un producto de Internet o la World Wide Web (WWW). Linux posee
         soporte nativo para varios protocolos de red, como lo son TCP/IP,
         AppleTalk, etc.

 El kernel, internemente, esta dividido en modulos que se ocupan cada uno de
 una tarea en especial. Una sobre-simplificacion de la estructura del kernel,
 se muestra en la figura 11.1.
                           
                          /--------------------\
                         | Programas de usuario |\
                          \--------------------/  |
                             \---|---|---|-------/            
                                 |   |   |                    PROGRAMAS
  # # # # # # # # # # # # # # # #|# #|# #|# # # # # # # # # # # # # # # # # # # # #
                                 |   |   |                     KERNEL
       _________________________\|/_\|/_\|/___________________________________
      |      .            Interfaz de llamdas al sistema                      |
       ||||
       _____\|/_____        _____\|/______       ____\|/_______     ___\|/__________
      | Manejo de   |      | Manejador de |     | Manejador de |   | Servicios de   |
      | sistemas de |      |  memoria     |     |  Procesos    |   | red abstractos |
      | archivos    |                  |  (sockets)     |
      | virtuales   |                                               |
       |                                                      \|/
            \|/                                                    ||
      ||                                              | Manejadores del |
      | Varios      |                                              |protocolo TCP/IP |
      | manejadores |                                              |_________________|
      | de sistemas |______________                                        |
      | de archivos |              \                                     \|/
       |                 |                             ||
          \|/                       \|/                            | Manejador de   |
      ||     ||                  | tarjeta de red |
      | Manejador   |     | Manejador de        |                  |  Ethernet      |
      | de discos   |     | Unidad de diskettes |                   |
      | rigidos IDE |     |                     |                          |
       |       |                           |
           |                         |                                     |               KERNEL
  # # # # #|# # # # # # # # # # # # #|# # # # # # # # # # # # # # # # # # #|# # # # # # # # # # # #
           |                         |                                     |               HARDWARE
          \|/                       \|/                                    |
   ||     ||                       \|/
   | Disco Rigido IDE |     | Unidad de diskettes |                 ||
   |__________________|     |_____________________|                 | Tarjeta Ethernet |
                                                                     

                 Figura 11.1: Partes importantes del kernel.

 11.2 LA INTERACCION

 Como dijimos anteriormente, en Linux, a diferencia de otros Unix, ni el
 programador ni el usuario interactuan directamente con el kernel. Existen
 dos mecanismos que son utilizados para interactuar con el S.O. Ambos
 terminan ejecutando "llamadas al sistema" (system calls) que son funciones
 que el kernel provee como servicios, y cada una de ellas tiene un rol
 predeterminado, por ejemplo: abrir un archivo, iniciar un proceso, mandar
 un mensaje a otro proceso, etc. Si la comunicacion usuario-sistema operativo
 se realizara mediante llamadas al sistema, seria todo muy engorroso y
 tedioso, ya que las mismas implementan funciones de muy bajo nivel. Para,
 por ejemplo, listar los contenidos de un directorio tendriamos que ejecutar
 una gran cantidad de llamadas al sistema explicitamente, lo que es inviable
 para un usuario.

 Las librerias del sistema y los programas de usuario nos brindan una
 interfase mas amigable para poder comunicarnos con el sistema.

 11.2.1 LAS LIBRERIAS DEL SISTEMA

 Las librerias del sistema definen un conjunto de funciones mediante las
 cuales las aplicaciones pueden interactuar con el kernel y que implementan
 la mayoria de la funcionalidad del S.O. que no necesita los privilegios
 que posee el codigo del kernel.

 La interfaz del S.O., visibles a las aplicaciones, no es mantenida
 directamente por el kernel, sino que las aplicaciones hacen llamadas a las
 librerias del sistema que luego llaman a los servicios del S.O. si es
 necesario.

 Las librerias del sistema proveen muchos tipos de funcionalidad. En el nivel
 mas simple, permiten a las aplicaciones realizar pedidos de servicios al
 kernel. Las librerias pueden, tambien, proveer versiones mas complejas de
 las llamadas al sistema. Por ejemplo: las funciones de libreria del lenguaje
 C de manejo de archivos, estan todas implementadas en las librerias del
 sistema, permitiendo asi un control mas avanzado de entrada-salida de
 archivos que aquel que el kernel provee. Las librerias del sistema tambien
 contiene rutinas que no corresponden a las llamadas al sistema como lo
 pueden ser algoritmos de ordenamiento, funciones matematicas, etc.

 11.2.2 LAS UTILIDADES DEL SISTEMA

 Las utilidades del sistema o programas del usuario, son programas que
 realizan tareas individuales y especializadas. Algunas utilidades del
 sistema se invocan una unica vez para inicializar y configurar algun
 aspecto del sistema, otras; conocidas como "demonios", se ejecutan
 permanentemente en "background" y manejan tareas de conexiones de red,
 actualizacion de "archivos de log", aceptacion de pedidos de inicio de
 sesion, etc.

 No todas las utilidades del sistema sirven para adminsitrar puntos claves
 del sistema. El entorno del S.O. Linux contiene un gran numero de utilidades
 estandar para realizar tareas simples, de todos los dias, como son listar
 directorios, mostrar el contenido de un archivo, etc. Por mas que estas
 utilidades no realicen tareas del S.O. en si son una parte muy importante
 del S.O. Linux.

 11.3 QUE SON LOS MODULOS?

 El kernel de Linux es un "kernel monolitico". Esto quiere decir que es un
 unico y largo programa donde todos los componentes funcionales del mismo
 tiene acceso a todas las estructuras de datos internas y sus rutinas. Esta
 caracteristica evidencia una falta de modularidad en el diseo del kernel.
 Por ejemplo, si queremos agregar un dispositivo al sistema, digamos una
 tarjeta de red, y el manejador de dispositivo no se encuentra compilado
 en el kernel, tendremos que volver a compilar "TODO" el kernel, que, como
 veremos mas adelante, es un proceso que consume mucho tiempo.

 Para evitar estas situaciones se aplica una estrategia parecida al uso de
 librerias compartidas por los programas de usuario en tiempo de ejecucion.
 Una gran cantidad de funcionalidad del kernel puede ser compilada como
 "modulos" y el kernel puede cargar y descargar los mismos a medida que los
 necesita. El kernel no necesita saber que modulos van a ser cargados, los
 mismos son verdaderamente componentes independientes.

 Los modulos se cargan bajo demanda, es decir cuando son necesitados para
 satisfacer el pedido del algun proceso, y se ejecutan en modo privilegiado
 como todo el codigo del kernel de Linux, y, como consecuencia tienen acceso
 completo a las capacidades del hardware de la maquina donde se ejecutan.

 Teoricamente, no existe ninguna restriccion en las tareas que un modulo
 debe realizar; tipicamente, un modulo puede implementar un manejador de
 dispositivo, un sistema de archivos o un protocolo de red.

 Existen muchas razones por las cuales es conveniente la utilizacion de
 modulos del kernel.

 El codigo de Linux es gratis, por lo tanto cualquier persona que quiera
 desarrollar un nuevo manejador de dispositivos puede insertarlo en el
 kernel, compilarlo y reconstruir el kernel, instalarlo y reiniciar el
 sistema con la nueva funcionalidad, pero esta tarea se puede volver
 altamente tediosa ya que cada vez que la persona modifique el manejador
 de dispositivo debera reconstruir e instalar el kernel para poder testearlo.
 Si se utilizan modulos, se puede compilar solamente el modulo y ser
 insertado y eliminado del kernel sin necesidad, siquiera, de reiniciar el
 sistema !! :)

 Finalmente, los modulos del kernel permiten al sistema Linux ser configurado
 con un kernel minimo estandar sin ningun manejador extra formando parte del
 mismo. Cualquier modulo que el usuario necesite puede ser cargado
 explicitamente al iniciarse el sistema o cargado automaticamente por el
 sistema al realizarse una demanda y descargado cuando el sistema detecte
 que ya no se necesita.

 11.4 PERSONALIZANDO EL KERNEL

 Una de las caracteristicas mas importantes del S.O. Linux es su
 flexibilidad, ya que es posible que podamos "poner a punto" el kernel y
 hacerlo a la medida de nuestro sistema, algo es totalmente imposible en
 otros S.O. comerciales.

 El hecho de que el S.O. Linux se distribuye con su codigo fuente completo,
 hace que podamos elegir que queremos que forme parte del kernel y que
 queremos dejar afuera. Por ejemplo: Linux posee una gran cantidad de
 manejadores de dispositivos SCSI, pero si nosotros no poseemos ningun
 dispositivo de este tipo, entonces podemos hacer que el codigo de estos
 manejadores no se compile ni se incluya en la construccion del kernel,
 obteniendo asi un kernel mas pequeo que ocupara menos memoria. Ya que,
 como dijimos antes, el kernel es la parte del S.O. que se encuentra
 residente en memoria, es importante reducir el tamao del mismo para
 liberar mas memoria para los procesos. Gracias a esta caracteristica, Linux
 exige mucha menor cantidad de memoria para trabajar que otros S.O. Por esto
 es totalmente viable configurar un kernel minimo, para trabajar, por
 ejemplo, en una maquina Intel 80386 con 2 Mb de memoria Ram.

 La personalizacion del kernel es una tarea que exige que tengamos un alto
 grado de conocimiento de las caracteristicas del hardware y de los servicios
 que necesitamos que funcionen en nuestro sistema. Un punto clave en la
 personalizacion del kernel es la configuracion del mismo.

 11.4.1 ELIGIENDO LA CONFIGURACION ADECUADA

    NOTA: Suponiendo que tenemos las fuentes del kernel instaladas
          correctamente, las mismas se encontraran en el directorio
          /usr/src/linux y todos los comandos que se muestran en la
          discusion que sigue deben ser ejecutados en ese directorio,
          salvo que se indique lo contrario. En la seccion 11.5.2 se
          dan las instrucciones para realizar la instalacion de las
          fuentes del kernel, ya sea porque no se encuentran instaladas o
          porque queremos instalar una nueva version.

 Cuando configuramos el kernel, estamos eligiendo los servicios que queremos
 que formen parte del mismo. Existen varias formas de realizar esta
 configuracion. Las mismas son:

 make config  Solo necesita que tengamos corriendo la shell bash. Ejecuta
              un script que nos va realizando una serie de preguntas. Se
              vuelve un proceso tedioso y no tenemos forma de volver atras
              en caso de un error.

 make menuconfig  Es una interfaz basada en menues de configuracion. Tenemos
                  un menu principal que se divide en sub-menus de acuerdo a
                  una serie de items. Es mucho mas comodo de utilizar y no
                  requiere interfaz grafica.

 make xconfig  Solo para aquellos que puedan ejecutar el sistema X Windows.
               Es una interfaz basada en ventanas y botones. Es mucho mas
               comoda para trabajar.

 En base a las caracteriticas de nuestro sistema, debemos elegir una
 herramienta de configuracion de las tres enumeradas anteriormente y asi
 comenzar la configuracion.

 ELECCIONES DE LAS OPCIONES

 Sin importar de que herramienta usemos para configurar el kernel, tendremos
 que seleccionar una opcion para cada item del kernel. Cada item posee una
 opcion "y" (yes) y otra "n" (no). Algunas poseen una opcion "m" (module)
 que significa que se compilara ese item pero no directamente dentro del
 kernel, sino como un modulo independiente.

 A continuacion describiremos las opciones basicas a tener en cuenta al
 momento de compilar el kernel. Esta lista, obviamente, es no exhaustiva y
 no prentende ser una guia precisa de la configuracion de un kernel, sino
 que trata de ser una ayuda para un novato a la hora de configurar un kernel.

 CODE MATURITY LEVEL OPTIONS: El S.O. Linux se encuentra en constante
 evolucion. Por lo tanto siempre existen caracteristicas que se encuentran
 en un estado experimental. Lo que quiere decir que algunas cosas no se
 encuentran totalmente testeadas y pueden ser peligrosas para el sistema.
 Podemos elegir que el configurador nos deje o no agregar caracteristicas
 experimentales al kernel. En general, las caracteristicas experimentales
 son utilizadas por desarrolladores y se recomienda que los usuarios
 novatos las dejen de lado.

 PROCCESOR TYPE AND FEATURES: Aqui configuramos el tipo de procesador de
 nuestro sistema. Otro item importante es si deseamos emulacion de
 instrucciones matematicas; maquinas superiores a 486 SX poseen coprocesador
 matematico en hardware, por lo que si tenemos una maquinas de estas debemos
 contestar que no.

 LOADABLE MODULE SUPPORT: Aqui especificamos si queremos soporte para modulos
 en nuestro kernel. Si vamos a compilar algun servicio como modulo es
 indispensable responder "y" a la pregunta Enable lodable module support ?.

 GENERAL SETUP: En esta opcion elegimos parametros generales de nuestro
 sistema. Elegimos si queremos soporte para trabajar en red, soporte para
 dispositivos PCI, soporte para puertos paralelos (indispensable para
 instalar una impresora, o cualquier dispositivo que utilice el puerto
 paralelo) y otro items avanzados como lo son Advanced Power Management
 (para computadoras portatiles), mecanismos de comunicacion entre procesos
 y soporte para distintos formatos de archivos ejecutables.

 PLUG AND PLAY SUPPORT: Si tenemos algun dispositivo periferico que sea
 compatible con la norma Plug and Play, debemos contestar "y" al item Plug
 and Play support.

 BLOCK DEVICES: En esta seccion elegimos el tipo de los dispositivos de
 almacenamiento de archivos que vamos a utilizar, como por ejemplo, si
 queremos soporte para unidad de diskettes, para discos rigidos IDE, CD-ROM's
 IDE/ATAPI, dispositivos de cinta magnetica, soporte para discos ULTRA-DMA, y
 otros dispositivos de bloque avanzados. Si estamos desorientados de que
 elegir se recomienda soporte para discos IDE, diskettera normal, CD-ROM's
 ATAPI y dejar el resto de las opciones predeterminadas.

 NETWORKING OPTIONS: Editar solo si necesitamos soporte para trabajar en red.
 Esta seccion esta llena de opciones avanzadas que en general, solo son
 seteadas por un adminsitrador de red. Sin embargo, podemos optar en algunos
 items. Si queremos soporte para trabajo en red, debemos asegurarnos de que
 el item TCP/IP Networking este seleccionado. El resto de las opciones
 podemos dejarlas en su estado predeterminado, a no ser que sepamos lo que
 estamos haciendo !!! Si nececitamos conectividad con maquinas corriendo
 Novell/Netware debemos seleccionar el soporte para protocolo IPX.

 SCSI SUPPORT: Solo si tenemos algun dispositivo SCSI para configurar. En
 esta seccion hay una gran variedad de dispositivos para elegir. Debemos
 averiguar que marca y modelo es el nuestro y que caracteristicas posee
 para seleccionar el adecuado. Podemos elegir que el manejador de
 dispositivos se compile como modulo si no sera frecuentemente utilizado.

 NETWORK DEVICE SUPPORT: En esta seccion seleccionamos que tipo de interfases
 de red instalaremos en nuestro sistema. Hay soporte para una gran cantidad
 de tarjetas Ethernet, tanto ISA, VLB o PCI. Tenemos soporte para los
 dispositivos Frame Relay, FDDI, etc. Si vamos a conectar dos maquinas
 mediante un cable debemos elegir PLIP (cable paralelo) o SLIP (cable serie).
 Para este ultimo tambien podemos elegir soporte para PPP (Point to Point
 Protocol), el cual es indispensable si queremos realizar conexiones a
 Internet mediante un ISP (Internet Service Provider) Proveedor de Servicios
 Internet.

 CHARACTER DEVICES: Aqui seleccionamos que dispositivos de caracter queremos
 utilizar. Se recomienda elegir consolas virtuales, soporte para puertos
 serie estandar, soporte para impresora en puerto paralelo, soporte para
 mouse (no serial) en caso de tener un mouse PS/2, Logitech, etc.

 FILESYSTEMS: Esta es una de las secciones mas importantes de la configuracion 
 del kernel. Aqui elegimos que tipos de sistemas de archivos podran ser
 accedidos mediante nuestro kernel. Es indispensable el soporte para ext2fs
 que es el sistema de archivos de Linux. Se deben elegir FAT y VFAT para
 poder leer y escribir sistemas de archivos de MS-DOS y Windows 95
 respectivamente, el sistema de archivos ISO9660 para leer CD-ROM's de datos,
 las extensiones Joliet para CD-ROM's de Microsoft nos permiten entender
 el formato de nombres largos de los CD-ROM's que tienen este formato; el
 soport para NTFS nos permite leer informacion de los sistemas de archivos
 de Windows NT; los demas son sistemas de archivos raramente utilizados y,
 es preferible desactivarlos, si no tenemos la necesidad de utilizarlos. El
 codigo para poder entender los sistemas de archivos adicionales se suele
 compilar como modulos ya que no son utilizados constantemente y podemos
 aprovechar para poder reducir el tamao del kernel.

 NATIVE LANGUAGE SUPPORT: En esta seccion podemos elegir que tipo de lenguaje
 nativo queremos utilizar. En general se seleccionan las opciones Codepage 437,
 Codepage 850 y NLS ISO-8859-1 (Latin 1) para nuestro pais y paises con
 lenguajes similares. Los demas codigos de paginas y de caracteres se
 utilizan para otros lenguajes: hebreo, turco, griego, arabe, etc.

 SOUND: En esta seccion seleccionamos si queremos o no soporte para tarjeta
 de sonido y en caso de ser afirmativa la respuesta elegimos para que tipo
 de tarjeta queremos tener soporte. Las tarjetas mas conocidas y utilizadas
 son las tarjetas Sound Blaster, Pro Audio Spectrum, Microsoft Sound System,
 Ensoniq Soundscape, etc. Es necesario aclarar que el driver de Sound Blaster
 es solo para tarjetas que son 100% compatibles con Sound Blaster, que no es
 el caso de la mayoria de las tarjetas de sonido genericas que se venden
 para computadoras personales. Existen muchisimos modelos que claman ser
 compatibles Sound Blaster, pero nos engaan, ya que la compatibilidad la
 emulan por software cargando un manejador de dispositivo residente (que
 solo funciona con MS-DOS o Windows) que se comunica con la tarjeta. En
 Linux, obviamente no podremos cargar este manejador y tampoco podremos hacer
 funcionar la tarjeta con el manejador de Sound Blaster. Sin embargo, algunas
 de estas tarjetas son compatibles con MAD16 y funcionan perfectamente con
 este manejador. Encontramos, tambien soporte para muchas otras tarjetas
 menos conocidas que las nombradas anteriormente, y ademas soporte para poder
 trabajar con MIDI. Se recomienda compilar los manejadores que necesitemos
 como modulos ya que resulta muy practica y facil la instalacion y la
 configuracion posterior de la tarjeta de sonido.

  NOTA: Cada item posee un cuadro de ayuda donde se explica exactamente
        para que sirve. En caso de desorientacion o desconociemiento se
        recomienda LEER la explicacion que alli se encuentra. En caso de
        dudas, dejar la opcion predeterminada.

 CODIGO INTEGRADO EN EL KERNEL VS MODULOS

 Cuando debemos decidir si un item debe ser compilado como parte del kernel o
 como modulo independiente debemos tener en cuenta los siguientes puntos:

  * Si el servicio va a ser utilizado infrecuentemente y su eficiencia no
    es critica para el funcionamiento del sistema, entonces nos conviene
    que se instale como modulo, ya que no ocupara memoria mientras no se
    necesite.

  * Hay servicios que es necesario que se encuentren instalados al iniciarse
    el sistema. En estos casos es conveniente que se instalen como parte del
    kernel, ya que los modulos se suelen cargar despues de que el sistema se
    inicio y consecuentemente luego de que fuera necesitado.

  * Cuando un servicio se compila como modulo tenemos la ventaja de que no
    ocupara espacio innecesario, pero tenemos la desventaja de que cuando
    queremos utilizar el modulo tenemos una sobrecarga. Cuando queremos
    utilizar un servicio que ha sido compilado como modulo, debemos cargarlo
    explicitamente o el mismo puede ser configurado para ser cargado
    automaticamente, pero de todas formas, el kernel debe realizar una serie
    de operaciones para vincular los modulos dinamicamente y cargarlos para
    que puedan ser utilizados. Estas operaciones no son necesarias cuando
    compilamos el servicio como parte del kernel.

  * Si el tamao del kernel nos condiciona rigidamente, entonces debemos
    utilizar los modulos tanto como sea posible. Es normal configurar un
    kernel que haga uso intensivo de modulos y lograr que el tamao del
    mismo ronde los 400 K.

 11.4.2. COMPILANDO EL KERNEL

 Luego de que hayamos configurado nuestro kernel pasamos a la etapa donde
 construimos el mismo. Esta etapa es un proceso facil de realizar (desde el
 punto de vista del usuario), pero, en contrapartida, nos lleva mucho tiempo.
 Este proceso realiza la compilacion de todos los elementos seleccionados
 en la etapa de configuracion. La compilacion es un proceso que realiza un
 uso intensivo del procesador y el tiempo que tardaremos en compilar el
 kernel depende exclusivamente de la velocidad y potencia de nuestro
 procesador y de la cantidad de memoria del sistema. Dependiendo de nuestra
 maquina podemos tardar desde 15 minutos hasta 1 hora o mas todavia.

   NOTA: Si todavia no le tomaron el gustito a los modulos, prueben de
         olvidarse de compilar algo como parte del kernel y luego tener que
         volver a compilarlo completamente solo para agregar ese servicio.

 CALCULANDO LAS DEPENDENCIAS

 Las fuentes del kernel estan formadas por un gran numero de archivos y
 componentes que se encuentran vinculados por relaciones de dependencia.
 Estas relaciones de dependencia entre los objetos del kernel deben ser
 calculadas de acuerdo a la configuracion del kernel que hayamos elegido.
 El siguiente comando calculara las dependencias:

  ==> make dep

 LIMPIANDO LO VIEJO

 Si no es la primera vez que utilizamos las fuentes del kernel para
 compilarlo, debemos tener en cuenta que existen archivos compilados del
 kernel anterior y es indispensable eliminarlos antes de comenzar el proceso
 de construccion. El siguiente comando se ocupara de limpiar todos los
 archivos innecesarios:

  ==> make clean

 CONSTRUYENDO EL KERNEL

 Para compilar los kernels 2.2.x debemos asegurarnos de tener instalada la
 version 2.7.2 del compilador de C/C++ gcc, o alguna mas nueva. Para
 averiguar esto podemos ejecutar el siguiente comando:

  ==> gcc --version

  Para construir el kernel debemos ejecutar

  ==> make zImage

 Este es proceso que tarda mas tiempo y genera una imagen comprimida del
 kernel. Una vez que este proceso termina el kernel se encuentra listo para
 ser instalado. En caso de haber seleccionado demasiados servicios para que
 sean compilados como parte del kernel, el proceso de construccion se
 abortara quejandose de esto. Para contrarrestar esto podemos probar con el
 siguiente comando:

  ==> make bzImage

 Si el proceso se sigue quejando, entonces debemos eleminar alguno de los
 servicios elegidos o seleccionarlos para que se compilen como modulos, y
 luego volver a calcular las dependencias, limpiar los archivos y comenzar
 de nuevo la construccion.

 11.4.3 COMPILANDO LOS MODULOS

 Si en la etapa de configuracion seleccionamos algun item para que sea
 compilado como modulo, entonces debemos ejecutar el siguiente comando:

  ==> make modules

 Este comando realiza la compilacion de los modulos que seleccionamos en la
 etapa de configuracion.

 11.4.4 INSTALANDO LOS MODULOS

 En lo que respecta a los modulos, nos resta instalarlos. Los modulos son
 normalmente instalados en el directorio /lib/modules. En este directorio
 encontraremos un subdirectorio por cada version kernel para la que hayamos
 instalado modulos anteriormente.

 Ejecutando el siguiente comando, instalaremos los modulos en ese directorio
 bajo el subdirectorio correspondiente a la version del kernel que estemos
 ejecutando.

  ==> make modules_install

 11.4.5 INSTALANDO EL NUEVO KERNEL

 Una vez que tenemos nuestro kernel compilado debemos instalarlo para que el
 sistema comience a trabajar con el mismo. La mayoria de los usuarios de
 Linux utilizan el programa LILO (LInux LOader) para instalar el kernel. LILO
 es un programa facil de utilizar, aunque el archivo de configuracion
 /etc/lilo.conf suele confundir un poco a los usuarios novatos. El archivo
 de configuracion debe parecerse al que se muestra en la figura 11.2.

  # cat /etc/lilo.conf
  boot=/dev/hda
  map=/boot/map
  install=/boot/boot.b
  image=/boot/vmlinuz
          label=linux
          root=/dev/hda1
          read-only

         Figura 11.2: Un archivo de configuracion del programa LILO.

  Tres puntos importantes a tener en cuenta:

  1. La linea image=...: Aqui le indicamos a LILO la ruta donde se encuentra
                         la imagen comprimida del kernel.

  2. La linea label=...: Esta opcion le indica al programa que estiqueta usar
                         para ese kernel. La etiqueta es util en caso de tener
                         mas de un S.O. en la misma maquina, ya que LILO nos
                         permite iniciar cualquiera de ellos eligiendo la
                         respectiva etiqueta.

  3. La linea root=...: Con esta opcion le indicamos a LILO cual es la
                        particion raiz de nuestro sistema.

 Debemos configurar estas opciones en el archivo de configuraciones,
 guardarlo y luego copiar la imagen comprimida del kernel que se encuentra
 en el dirctorio /usr/src/linux/arch/i386/boot bajo el nombre zImage o
 bzImage, segun hayamos elegido al construirlo, a el lugar que le fue
 indicado a LILO en el archivo de configuracion.

 Luego debemos ejecutar lilo (o /sbin/lilo si la shell no lo encuentra). Esto
 hara que LILO lea el archivo de configuracion e instale el nuevo kernel bajo
 las opciones especificadas.

 Para poder trabajar con el nuevo kernel, resta reiniciar el sistema. La
 instalacion de un nuevo kernel es uno de los unicos motivos por los cuales
 es necesario reiniciar el sistema, ya que no nos queda otra opcion.

 En general podremos reiniciar el sistema ejecutando el comando:

  ==> reboot

   o equivalentamente

  ==> init 6

 11.4.6 CARGANDO Y DESCARGANDO LOS MODULOS

 Una vez que iniciamos el sistema con el nuevo kernel y verificamos que todo
 funciona correctamente, podemos comenzar a probar los modulos seleccionados
 y compilados anteriormente.

 Los comandos referidos a la manipulacion de modulos son los siguientes:

  * lsmod (list modules): Muestra una lista de los modulos cargados
                          actualmente.

  * isnmod (insert module): Carga un modulo en memoria como parte del kernel.

  * rmmod (remove module): Elimina un modulo cargado en memoria.

 Inicialmente, no se encuentra cargado ningun modulo en memoria. Por lo tanto,
 al ejecutar lsmod obtendremos una lista vacia:

  # lsmod
  Module             Size     Used by

 En la figura 11.3 se muestra el contenido de los directorios que contienen
 los modulos en un sistema.

 Ilustraremos la carga y descarga de los modulos con el modulo minix que nos
 permite montar sistemas de archivos del S.O. Minix. Veamos que pasa si
 queremos montar un diskette con sistema de archivo minix sin tener el modulo
 cargado:

  # mount -t minix /dev/fd0 /mnt/floppy
  mount: fs type minix not supported by kernel

 El comando mount nos indica que hay un error, ya que el sistema de archivos
 Minix no se encuentra soportado por el kernel. Para poder montar el sistema
 de archivos de Minix debemos cargar el modulo minix. Para cargar el mismo
 ejecutamos el comando insmod y luego verifiamos que haya sido cargado:

  # insmod minix
  # lsmod
  Module             Size     Used by
  minix             22568      0  (unused)

 Una vez que tenemos el modulo caragado como parte del kernel podemos montar
 tranquilamente el diskette. Notemos que el modulo esta cargado pero nadie lo
 esta utilizando. Veamos como montar el diskette:

  # mount -t minix /dev/fd0 /mnt/floppy
  # lsmod
  Module             Size     Used by
  minix             22568      1

 Como vemos, ahora el modulo esta siendo usado por 1 servicio ya que al
 montar el diskette el modulo se utiliza hasta que el mismo se desmonte. Una
 vez que ya no necesitamos utilizar el diskette lo desmontamos y luego
 verificamos que el modulo ya no esta siendo utilizado:

  # rmmod minix
  # lsmod
  Module             Size     Used by

 11.4.7 LAS DEPENDENCIAS ENTRE LOS MODULOS

 Asi como los distintos componentes que forman parte del kernel poseen
 dependencias, los modulos tambien se vinculan por relaciones de dependencia.
 En el caso del ejemplo anterior del modulo minix vimos que el mismo no
 depende de ningun otro modulo, por lo que podemos cargarlo directamente y
 comenzar a utilizarlo. No todos los modulos poseen esta caracteristica y,
 como consecuencia, puede no ser tan facil cargarlos.

  # pwd
  /lib/modules/2.2.5
  #ls *
  modules.dep

  block:
  loop.o

  fs:
  minix.o     msdos.o

  misc:
  ad1848.o    af_spx.o    ipx.o    mad16.o    sb.o    uart401.o

  net:
  8390.o      bsd_comp.o    dummy.o    ne.o    ppp_deflate.o

              Figura 11.3: Una serie de modulos instalados

 Suponiendo el mismo conjunto de modulos de la figura 11.3 queremos instalar
 otro modulo.

 Uno de los items que seleccionamos para que sea compilado como modulo en la
 etapa de configuracion es el manejador de dispositivo de una placa de red
 compatible NE2000. Una vez que examinamos el subdirectorio net encontramos
 el modulo ne y lo instalamos con el comando insmod de la siguiente forma:

  # insmod ne
  /lib/modules/2.2.5/net/ne.o: unresolved symbol ei_open
  /lib/modules/2.2.5/net/ne.o: unresolved symbol ethdev_init
  /lib/modules/2.2.5/net/ne.o: unresolved symbol ei_interrupt
  /lib/modules/2.2.5/net/ne.o: unresolved symbol NS8390_init
  /lib/modules/2.2.5/net/ne.o: unresolved symbol ei_close

  Que paso ?

 La respuesta es la siguiente: el modulo no puede resolver ciertos simbolos.
 Esto quiere decir que depende de algun otro modulo. Por lo tanto antes de
 cargar el modulo "ne" debemos cargar los modulos de los cuales depende.
 Pero...  cuales son los modulos de los que depende ?. En este caso, una
 detallada examinacion de los mensajes de error del comando insmod pueden
 hacernos sospechar que el numero 8390 que por ahi anda dando vueltas
 implica que el modulo 8390, que se encuentra en el mismo directorio que ne,
 es necesario para poder cargarlo. Por lo tanto, probamos:

  # insmod 8390
  # insmod ne

 Efectivamente esto funciono, y lo podemos verificar con el comando lsmod.
 En la tabla que nos muestra este comando vemos que el modulo 8390 es
 utilizado por el modulo ne.

  # lsmod
  Module             Size     Used by
  ne                 5980      1
  8390               5940      0  [ne]

 Esta aproximacion, claramente, no es practica. Un modulo puede depender de
 varios y podemos tener situaciones donde las dependencias entre modulos son
 transitivas, es decir, que un modulo M3 depende de otro modulo M2 y este, a
 su vez, depende de otro modulo M1. Asi vemos que las cosas se complican; si
 no contamos con una herramienta que realice automaticamente estas tareas de
 resolusion de dependencias, la carga y descarga de modulos se vuelve una
 tarea bastante complicada.

 Por suerte, existen dos utilidades que nos resuelven estos problemas
 ideseables.

 11.4.8 UNA CARGA MAS INTELIGENTE

 El programa depmod es una utilidad que sirve para calcular automaticamente
 las dependencias entre los modulos. Puede ser utilizado de varias formas,
 pero la mas comun de ellas es la siguiente:

  ==> depmod -a

 Este comando ejecutara depmod con la opcion -a (all) y asi calculara todas
 las dependencias entre los modulos. Este comando es ejecutado, usualmente,
 como parte del inicio del sistema.

 Una vez que se calculan las dependencias entre los modulos, podemos cargar
 los modulos sin saber que dependencias tienen, ya que el sistema se ocupara
 de cargar los modulos necesarios (de acuerdo a las dependencias) de forma
 totalmente transparente al usuario. Para poder realizar la carga de los
 modulos de esta forma, debemos utilizar el comando modprobe.

 Veamos un ejemplo de esta estrategia:

 Queremos cargar el modulo mad16, que sabemos es el manejador de dispositivo
 de un tarjeta de sonido. Supongamos que la misma esta configurada para
 trabajar en el puerto 0x530, utiliza la interrupcion (IRQ) 10 y el acceso
 directo a memoria (DMA) 1. Por supuesto, no tenemos las mas minima idea de
 que modulos es necesario cargar para que mad16 funcione correctamente. No
 hay problema, ejecutando los siguientes comandos todo se hara de forma
 automatica y transparente.

  # lsmod
  Module             Size     Used by
  # depmod -a
  # modprobe mad16 io=0x530 irq=10 dma=1
  # lsmod
  Module             Size     Used by
  mad16              6548      0  (unused)
  uart401            5572      0  [mad16]
  ad1848            15088      0  [mad16]

 Como vemos, al comenzar no tenemos ningun modulo cargado. Antes de cargar
 el modulo mad16 realizamos el calculo de las relaciones de dependecia entre
 los modulos. Luego cargamos el modulo mad16. Notemos que este modulo (como
 muchos de los que implementan manejadores de dispositivos de placas de
 sonido) necesitan parametros adicionales para poder ser cargados. En este
 caso son necesarios el puerto de entrada/salida, la interrupcion y el acceso
 directo a memoria que utiliza la misma. Luego de cargar el modulo,
 realizamos un listado de los modulos que se encuentran cargados y
 descubrimos que el modulo mad16 posee dos dependencias: uart401 y ad1848.
 Estos modulos fueron cargados automaticamente para poder cargar el modulo
 mad16.

 Para descargar el modulo y todas sus dependencias (que no se encuentren en
 uso) podamos ejecutar modprobe -r:

  # modprobe -r mad16
  # lsmod
  Module             Size     Used by

 11.5 ACTUALIZANDO NUESTRO KERNEL

 Una de las grandes ventajas del S.O. Linux es su desarrollo. El kernel del
 sistema se encuentra en constante actualizacion y desarrollo, a tal punto
 que podemos disponer de una nueva version del mismo cada, mas o menos, una
 o dos semanas. Comparemos esto con la frecuencia de actualizacion de otros
 S.O., si es que tiene actualizacion :)

 Es importante actualizar nuestro kernel ya que a medida que los kernels
 evolucionan se corrigen muchos "bugs", son capaces de trabajar con nuevos
 dispositivos, se agrega soporte para otros sistemas de archivos, pueden
 mejorar el manejo de puntos claves (memoria, procesos, etc.), pueden ser
 mas rapidos y mas estables, etc.

 11.5.1 OBTENIENDO EL KERNEL

 Existen varias formas de obtener las fuentes del kernel. Una de ellas es
 mediante Internet ya que existen varios sitios donde se publican las mismas.
 Ver al apendice A para obtener las direcciones de los sitios. Existen,
 tambien varias distribuciones en CD-ROM's que traen las fuentes de los
 kernels.

 Un punto importante a tener en cuenta al momento de conseguir las fuentes
 del kernel es la version de las mismas.

 VERSIONES DEL KERNEL

 Las fuentes del kernel poseen un sistema de numeracion muy simple. Cualquier
 version par de las fuentes representa un kernel estable, por ejemplo 2.0 o
 2.2. Una version impar representa un kernel en estado experimental o en
 desarrollo (las famosas versiones "beta"), por ejemplo 2.1.

 A su vez sobre cada version se publican varios "releases", es decir
 subversiones de los mismos. Asi podemos tener versiones como 2.0.32,
 2.1.125, 2.2.5, etc. En general, existen un gran numero de releases betas
 antes de publicar la siguiente version estable. Por ejemplo, antes de que
 se publicara la version 2.2 del kernel se realizaron mas de 130 releases del
 kernel 2.1. Podemos ver el grado de testeo y correccion de los kernels antes
 de ser denominados "estables" y por lo tanto ser considerados confiables y
 aceptables. La politica de los desarrolladores de Linux es testear
 intensivamente los kernels antes de publicar una nueva version estable, por
 lo que podemos estar seguros de que si la version es par es "realmente
 estable". Comparemos esto con las estrategias de desarrollo de otros S.O.

 11.5.2 INSTALANDO LAS FUENTES DEL KERNEL

 Las fuentes del kernel son provistas en un archivo agrupado y comprimido
 con el formato tar y gzip o alternativamente bzip2. Si la version es,
 digamos, 2.2.1, entonces el archivo se llamara linux-2.2.1.tar.gz o
 linux-2.2.1.tar.bz2. Estas fuentes deben ser instaladas dentro del
 directorio /usr/src.

 Como es posible que tengamos en ese mismo diretorio las fuentes de kernels
 de versiones anteriores, es recomendable realizar un par de cosas antes de
 descomprimir las nuevas fuentes. Supongamos que dentro del directorio
 /usr/src tenemos instaladas las fuentes del kernel 2.1.125 y queremos
 instalar las fuentes del nuevo kernel 2.2.5. El contenido del directorio
 /usr/src es el siguiente:

  # pwd
  /usr/src
  # ls -l
  lrwxrwxrwx    1 root     root        11 May 5 23:58 linux -> linux-2.1.125
  drwxr-xr-x   15 root     root      1024 May 5 23:50 linux-2.1.125
  -rw-r--r--    1 root     root  13721493 May 9 22:17 linux-2.2.5.tar.gz

 Las fuentes del kernel actuales deben encontrarse en el directorio linux.
 Es conveniente que se realice un directorio para cada version de las fuentes
 y crear un link simbolico linux que apunte al directorio respectivo. En
 este caso el link apunta al directorio linux-2.1.125 ya que es la unica
 version que tenemos.

 Si descomprimimos las nuevas fuentes en este momento tendremos un problema:
 En general, estos archivos comprimidos viene armados para que al
 descomprimirlos se instalen en el directorio linux, pero como nosotros
 tenemos el link simbolico apuntando al directorio linux-2.1.125, al
 descomprimir las fuentes, estas se instalaran en este ultimo directorio y
 sobrescribiran las fuentes del kernel 2.1.125. Para evitar esto, debemos
 eliminar el link simbolico antes de descomprimir las nuevas fuentes. En la
 figura 11.4 vemos como hacer para instalar correctamente las fuentes del
 kernel y conservar las anteriores.

  # rm linux
  # ls -l
  drwxr-xr-x  15 root    root      1024 May 5 23:50 linux-2.1.125
  -rw-r--r--   1 root    root  13721493 May 9 22:17 linux-2.2.5.tar.gz
  # tar -zxvf linux-2.2.5.tar.gz
  # ls -l
  drwxr-xr-x  15 root    root      1024 May 9 22:30 linux-2.1.125
  drwxr-xr-x  15 root    root      1024 May 5 23:50 linux-2.2.5
  -rw-r--r--   1 root    root  13721493 May 9 22:17 linux-2.2.5.tar.gz
  # mv linux linux-2.2.5
  # ls -l
  drwxr-xr-x  15 root    root      1024 May 5 23:50 linux-2.1.125
  drwxr-xr-x  15 root    root      1024 May 9 22:32 linux-2.2.5
  -rw-r--r--   1 root    root  13721493 May 9 22:17 linux-2.2.5.tar.gz
  # ln -s linux-2.2.5 linux
  # ls -l
  lrwxrwxrwx   1 root    root         9 May 9 23:33 linux -> linux-2.2.5
  drwxr-xr-x  15 root    root      1024 May 5 23:50 linux-2.1.125
  drwxr-xr-x  15 root    root      1024 May 9 22:32 linux-2.2.5
  -rw-r--r--   1 root    root  13721493 May 9 22:17 linux-2.2.5.tar.gz

       Figura 11.4: Descomprimiendo las fuentes del nuevo kernel.

 Para completar la instalacion del nuevo kernel debemos realizar un paso
 adicional para asegurarnos de que no tenemos ningun vinculo incorrecto.
 Debemos cambiar el directorio /usr/src/linux y ejecutar el siguiente
 comando:

  ==> make mrproper

 Ahora si tenemos las fuentes del kernel correctamente instaladas.


 CAPITULO 12

 ASPECTOS AVANZADOS DE LA SHELL

 Ya hemos discutido la utilizacion de la shell en el capitulo 6 y la hemos
 utilizado interactivamente de manera intensiva. Los usuarios utilizan la
 shell, en su gran mayoria, interactivamente de las siguientes formas:

  * Ingresando comandos simples (ls).

  * Utilizando las facilidades de generacion de nombres de archivos
    (ls *.tex).

  * Especificando redireccion de la entrada y/o salida (ls > iofile).

  * Construyendo caerias (ls | wc -l).

 Estas tecnicas son potentes y extremadamente utiles, pero solo son una
 pequea parte de las capacidades de la shell.

 Elegir una shell interactiva es en realidad una cuestion de gusto. Muchos
 usuarios prefieren la shell "C" para uso interactivo. La misma fue la
 primera shell que implemento una lista historica de los comandos para poder
 ser reutilizados facilmente sin tener que tipearlos nuevamente. Tambien fue
 la primer shell que implemeto el control de procesos, es decir, como poder
 manipular procesos que se ejecutan en background. Elegir una shell para
 escribir un scripts es una tarea mucho mas facil. Si las necesidades del
 usuario son modestas y se conocen las capacidades de la shell de "C",
 entonces es conveniente utilizarla, pero la mayoria de los usuarios, hoy,
 prefieren utilizar la shell de "Bourne" para escribir scripts.

 La shell de "Bourne" (sh) es la unica shell que se encuentra en todos los
 sistemas Unix, incluido Linux, que ademas posee la shell "Bourne Again"
 (bash) que es totalmente compatible con la shell de Bourne y agrega
 caracteristicas importantes y utiles de la shell de "Korn" (ksh) y la shell
 de "C" (csh). La shell de Bourne Again es la shell predeterminada de Linux.

 La shell de "Bourne" fue diseada desde un comienzo como un lenguaje de
 programacion, lo que explica las capacidades de la misma como lenguaje de
 programacion lo que la hace la shell mas ampliamente aceptada como lenguaje
 de programacion de scripts.

 Este capitulo no intenta desarrollar completamente las capacidades de la
 shell de Bourne como lenguaje de programacion, sino que pretende ser una
 introduccion a la programacion de scripts, tarea no indispensable para un
 usuario ordinario, pero que puede hacer que muchas de las tareas a realizar
 en el sistema sean mas faciles y practicas. Analizaremos tambien los aspectos
 de la shell que forman el entorno del usuario, como lo son: variables de
 entorno, variables de shell, el camino de busqueda (path), etc.

 12.1 PROGRAMAS DE SHELL (SRIPTS)

 Un script es cualquier comando o secuencia de comandos de Linux almacenados
 en un archivo de texto. Usualmente el termino de script se utiliza cuando
 el archivo solo contiene una simple secuencia de comandos; el termino
 programa de shell identifica un archivo que contiene una estructura de
 comandos mas compleja.

 Un usuario puede ejecutar un programa de shell o un script directamente
 ingresando el nombre del archivo en la linea de comandos. Los programas
 de la shell se tratan de la misma forma que cualquier otro ejecutable.
 Por supuesto, debemos tener permiso de ejecucion sobre el archivo que
 contiene el script y ademas la shell debe poder encontrar el archivo
 dentro del camino de busqueda (path).

 12.2 VARIABLES DE LA SHELL

 Como en cualquier lenguaje de programacion, las variables de la shell se
 utilizan para almacenar valores para luego poder ser utilizados. El termino
 variable sugiere que el valor de la misma puede cambiar durante el flujo
 de ejecucion.

 Las variables de la shell solo pueden guardar cadenas de texto (strings).
 Los numeros, en las variables de la shell, son almacenados como cadenas de
 caracteres.

 Para asignar valores a las variables utilizamos el comando de asignacion (=).
 El valor almacenado en una variable se denota como $var, donde var es la
 variable en cuestion. Siempre que usemos el nombre de la variable, este
 denotara el nombre de la variable y no su valor, a diferencia de la mayoria
 de los lenguajes de programacion. Veamos un ejemplo de esto en la figura
 12.1.

  # Boca = campeon
  bash: Boca: command not found
  # River=campeon
  # echo River
  River
  # echo $River
  campeon
  # echo $Boca

  # River=Capo
  # echo $River
  Capo

        Figura 12.1: Seteando y consultando variables de la shell.

 En esta figura vemos varias cosas interesantes ( Je, je ademas de que la
 shell no conoce a Boca y si a River :):

  * Debemos ser cuidadosos al utilizar el comando de asignacion, ya que la
    shell nos obliga a ponerlo inmediatamente depues del nombre de la
    variable, ya que sino la primer palabra es interpretada como un comando
    y, cuando la shell intenta ejecutarlo no lo encuentra.

  * El comando echo visualiza una linea de texto en la salida estandar.
    Cuando ejecutamos el primer comando echo, vemos que la linea de texto
    ingresada ("River") es visualizada en pantalla. Cuando utilizamos el
    simbolo $ antes del nombre de la variable River, la shell reemplaza
    $River por el valor de la variable, es decir la cadena "campeon".
    Esta cadena es la que es pasada como argumento al comando y el mismo
    la visualiza en pantalla.

  * Es muy importante comprender que la manipulacion de las vatiables y sus
    valores la realiza la shell y no el comando echo. 

  * Una variable pierde su valor anterior si es asignada de nuevo.

  * Una variable que no ha sido asignada tiene la cadena nula o vacia.

 Cuando queremos asignar a una variable una cadena de caracteres que contiene
 espacios debemos encerrar toda la cadena entre comillas. Vemos un ejemplo
 en la figura 12.2.

  # Boca=No existe
  bash: existe: command not found
  # Boca="No existe"
  # echo $Boca
  No existe
  #

    Figura 12.2: Utilizando comillas para asignar cadenas a las variables.

 12.2.1 EXPORTANDO VARIABLES DE LA SHELL

 Las variables de la shell que creamos son locales a la shell activa a no
 ser que sean exportadas explicitamente. El comando export nos sirve para
 exportar variables. Con el siguiente comando podemos exportar la variable
 var:

  ==> export var

 Si ejecutamos export sin argumentos obtendremos una lista de las variables
 exportadas.

 Este comando solo lista las variables exportadas de la shell actual.

 Una variable exportada permanece en ese estado hasta que la shell en la
 que fue marcada para exportacion sea terminada.

 12.2.2 VARIABLES AUTOMATICAS DE LA SHELL

 Las siguientes variables son seteadas automaticamente por la shell:

  $? Contiene el valor de salida retornado por el ultimo comando ejecutado.

  $$ Contiene el PID de la shell actual.

  $! Contiene el PID del ultimo proceso que se invoco en background.

  $# Contiene el numero de parametros que fueron pasados a la shell.

  $* Contiene la lista de argumentos actual.
                       
 Estas variables pueden ser utilizadas como todas las demas. Por ejemplo
 podemos utilizar la variable $$ para ver el numero de proceso de la shell
 actual.
    
  # ps
    PID TTY STAT  TIME COMMAND
    443   1 S    0:00 /bin/login -- tony
    451   1 S    0:00 -bash
    462   1 S    0:00 sh /usr/X11R6/bin/startx
    463   1 S    0:00 xinit /home/tony/.xinitrc --
    467   1 S    0:02 wmaker
    490   1 S    0:57 emacs -fn 9x15
    541  p7 S    0:00 /bin/bash
    594  p7 R    0:00 ps
  # echo $$
  541

 12.2.3 VARIABLES ESTANDAR DE LA SHELL

 El significado de una gran cantidad de variables ha sido estandarizado con
 el paso del tiempo. Esta variables son como todas las demas, pero tiene un
 significado convencional que debemos entender. Estas variables son llamdas
 usualmente variables de entorno.

 Podemos producir un listado de las variables actualmente asignadas con el
 comando set.

 Veamos un listado de ejemplo en la figura 12.3.

  # set
  BASH=/bin/bash
  BASH_VERSION=1.14.7(1)
  COLUMNS=104
  DISPLAY=:0
  ENV=/home/tony/.bashrc
  EUID=500
  HISTFILE=/home/tony/.bash_history
  HISTFILESIZE=1000
  HISTSIZE=1000
  HOME=/home/tony
  HOSTNAME=tonyx
  HOSTTYPE=i386
  IFS=

  LD_LIBRARY_PATH=/usr/local/qt/lib
  LINES=24
  LOGNAME=tony
  MAIL=/var/spool/mail/tony
  MAILCHECK=60
  MANPATH=/usr/local/qt/man:/usr/man:/usr/local/man
  OLDPWD=/home/tony/docs/linux
  OSTYPE=Linux
  PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:.
  PPID=490
  PS1=#
  PS2=>
  PS4=+
  PWD=/home/tony/docs/linux
  SHELL=/bin/bash
  TERM=dumb
  UID=500
  USER=tony
  USERNAME=tony

              Figura 12.3: Listado de variables de entorno.

 La mayoria de estas variables se crean durante el proceso de inicio de
 sesion (login) y son una parte muy importante de la funcionalidad del
 sistema. Algunas de las variables que forman parte de la lista de la figura
 12.3 son utilizadas por uno o dos programas particulares y no son de
 interes general. Vamos a detallar el significdo de las variables que tienen
 una importancia vital para nuestro dialogo con Linux y para que el trabajo
 de los programas y utilidades se desarrolle exitosamente.

  $HOME  Contiene el nombre del directorio home del usuario. Se setea al
         iniciarse la sesion y es utilizada por los programas que necesitan
         acceder a archivos almacenados en nuestra parte del sistema de
         archivos, por ejemplo, los programas que lee o escriben los archivos
         de configuracion e inicializacion llamados dot files, ya que
         comienzan con un punto y son ocultos (.Xdefaults .bash.profile
         .xinitrc, etc.).

  $PATH  Contiene la cadena de busqueda que la shell utiliza cuando busca los
         comandos a ejecutar.

  $IFS  Contiene los separadores internos entre campos (Internal Field
        Separators), que son usualmente espacios, tabulador y nueva linea.
        Los separadores de campos separan las palabras de los comandos.
        La linea en blanco que se encuentra despues de IFS es parte del
        valor de la variable.


  $LOGNAME $USER $USERNAME  Es el nombre de usuario (login). Se usan
                            alternativamente.

  $MAIL o $MAILPATH  Se utilizan si queremos ser notificados de la llegada
                     de nuevo correo electronico.

  $MAILCHECK  Es el intervalo, en segundos, entre chequeos de nuevo mail.

  $SHELL  Es el nombre de la shell de inicio. Es utilizada por programas que
          invocan a shells interactivas para utilizar sin necesidad de salir
          del programa. Un ejemplo es emacs.

  $PS1  Es la cadena que la shell utiliza como prompt primario.

  $PS2  Es la cadena utilizada como prompt secundario. Es utilizado cuando la
        shell detecta que los comandos estan obviamente incompletos y nos
        piden informacion adicional. Usualmente es un simbolo >.

  $TERM  Contiene el modelo de terminal utilizado. Algunos comandos necesitan
         conocer el tipo de terminal para poder generar una salida correcta.

 12.3 EL CAMINO DE BUSQUEDA (PATH)

 Cuando ingresamos un comando, la primera cosa que la shell hace es buscar
 el programa asociado. Pero, Donde es que lo busca? Muchas instalaciones
 de Linux contiene cientos de directorios y consumiria mucho tiempo buscar
 en todos los directorios. Para concentrar la busqueda, la shell del sistema
 mantiene un camino de busqueda (PATH), tambien conocida como cadena de
 busqueda.

 El PATH es una lista de directorios donde la shell busca los comandos
 ingresados. Los PATH's en general contiene en directorio /bin, el directorio
 /usr/bin, etc., ya que en estos directorios es donde se encuentran los
 comandos y utilidades estandar.

 El PATH puede ser modificado para que la shell busque en directorios
 adicionales, cuando ingresamos algun comando. Si la shell no encuentra en
 ninguno de los directorios el comando especificado, entonces muestra un
 mensaje diciendonos que no lo pudo localizar. Podemos consultar cual es la
 lista de directorios que forman parte del path ejecutando:

  ==> echo $PATH

 Historicamente, se trataba de mantener los PATH's con una longuitud pequea,
 ya que forzaban a la shell a invertir mucho tiempo en las busquedas, lo que
 terminaba resistiendo el tiempo de respuesta de la shell. Hoy, tanto la
 shell de Bourne como la shell de C, operan de una forma mas eficiente,
 manteniendo un "cache" de los comandos, es decir que recuerda donde se
 encuentran los comandos y por lo tanto solo realizan una sola vez la
 busqueda, no importa la cantidad de veces que utilicemos el comando.
 Similarmente es recomendable mantener un tamao aceptable en los directorios
 donde almacenamos los ejecutables. Nos lleva mucho menos tiempo realizar
 una busqueda en un directorio que contiene solo unos pocos archivos que en
 un directorio que contiene cientos de archivos.

 En algunos sistemas Unix, incluyendo a Linux, el PATH no contiene al
 directorio actual. Los usuarios acostumbrados a trabajar con MS-DOS se
 sentirar desorientados cuando la shell les muestre un mensaje de error
 diciendoles que no encontro un comando que se encuentra en el directorio
 actual (suponiendo que el directorio actual no forma parte del PATH). Para
 este problema tenemos dos soluciones:

  1. Ejecutar cada comando del directorio actual con el agregado del "./".
     Vemos un ejemplo en la figura 12.4.

      # ls -l
      total 1
      -rwxr-xr-x   1 tony   users           20 Jun  5 21:19 script1
      # cat script1
      echo Hola $USERNAME
      # script1
      bash: script1: command not found
      # ./script1
      Hola tony

      Figura 12.4: Ejecutando un comando que se encuentra en el directorio
                   actual.

  2. Agregar el directorio "." a nuestro PATH. Asi no importa en que
     directorio estemos, siempre se incluira el mismo como parte del PATH y
     la shell encontrara los comandos.

 12.4 CARACTERES ESPECIALES - "QUOTING"

 Desafortunadamente, muchos de los caracteres especiales utilizados por la
 shell (, ?, -, etc.) son utilizados por otros programas. El problema es
 que no hay tantos simbolos disponibles y siempre pueden aparecer conflictos.
 Cuando ejecutamos comandos interactivamente o cuando ejecutamos un script,
 la shell es el primer programa que recibe el texto respectivo. Si el texto
 de el/los comandos contiene caracteres especiales, estos seran interpretados
 por la shell, realizando, la misma, las modificaciones necesarias. Para que
 la shell no interprete estos caracteres especiales, debemos utilizar
 secuencias de escape. Al proceso de utilizar secuencias de escape se lo
 conoce como quoting.

 Cuando queremos enviar simbolos especiales a los programas, debemos
 utilizar secuencias de escape. Existen tres formas de especificar secuencias
 de escapes:

  1. Una barra invertida (\) sirve de escape para los caracteres que la
     siguen inmediatamente.

  2. Todos los caracteres encerrados entre comillas simples (') se encuentran
     bajo una secuencia de escape.

  3. Las comillas dobles (") sirven de escape para todos los caracteres que
     se encuentren entre un par de ellas, salvo los siguientes caracteres:

      $ \  

 Veamos varios ejemplos en la figura 12.5.

  # echo $USER
  tony
  # echo '$USER'
  $USER
  # echo \$USER
  $USER
  # echo "$HOME"
  /home/tony
  # echo "ls | wc -l"
  ls | wc -l

        Figura 12.5: Ejemplos de la utilizacion de caracteres y secuencias
                     de escape.

 12.5 ESTADO DE SALIDA DE LOS COMANDOS

 Cada comando que ejecutamos retorna un codigo que representa el estado de
 salida del comando. Cuando un comando se ejecuta exitosamente, retorna un
 codigo de salida que es cero (zero exit status). Por convencion, si un
 programa encuentra problemas serios en su ejecucion, retorna un codigo de
 estado de salida que es distinto de cero (non-zero exit status).

 Ejemplo: Si ingresamos el siguiente comando:
              
  ==> ls -l /dev/hda

 El comando retornara un codigo igual a 0, ya que el archivo que representa
 al primer disco rigido de la maquina existe. Sin embargo, si ingresamos el
 comando:

  ==> ls -l /dev/hdz

 El comando retornara  un codigo distinto de 0, ya que el archivo de
 dispositivo especificado no existe y el comando ls encontrara el error.

 La variable de entorno $? contiene el codigo de estado de salida del ultimo
 comando ejecutado y podemos consultarla en caso de querer averiguar el
 codigo de estado de salida de los comandos. Vemos un ejemplo de esto en la
 figura 12.6.

  # ls -l /dev/hda                                       
  brw-rw----   1 root     disk     3,    0 Sep  7  1994 /dev/hda
  # echo $?
  0
  # ls -l /dev/hdz
  ls: /dev/hdz: No such file or directory
  # echo $?
  1

          Figura 12.6: Consultando el estado de salida de los comandos.  

 12.6 LOS ARGUMENTOS

 En los programas de la shell, los argumentos de linea de comandos se
 encuentran disponibles en una serie de variables numeradas. $1 es la
 variable que contiene el primer argumento, $2 contiene el segundo argumento,
 y asi siguiendo. Estas variables representan parametros posicionales.

 Existen dos variables especiales que representan informacion adicional
 acerca de los argumentos:

  * $0  Representa el valor del argumento 0 que siempre es el nombre del
        programa ejecutado.

  * $#  Contiene el numero de parametros ingresados en la linea de
        comandos.

 El programa que muestra la figura 12.7 toma como entrada 4 argumentos y
 como salida retorna los 4 argumentos en orden invertido. El programa fue
 realizado utilizando estas variables que representan los argumentos.

  # cat reverse
  if [ $# -eq 4 ]
  then
         echo $4 $3 $2 $1
  else
         echo Uso: $0 arg1 arg2 arg3 arg4
  fi
  # reverse
  Uso: $0 arg1 arg2 arg3 arg4
  # revese 12 34 56 78
  78 56 34 12
  #

      Figura 12.7: Un programa que utiliza las variables de argumentos.

 12.7 ESTRUCTURAS DE CONTROL

 Como cualquier otro lenguaje de programacion, el lenguaje de programacion
 de la shell nos brinda la posiblidad de utilizar estructuras de control. En
 el ejemplo de la figura 12.7, vimos de forma adelantada, el condicional if.

 A continuacion veremos un resumen de las estructuras de control que provee
 el lenguaje de programacion de la shell.

 12.7.1 CONDICIONALES SIMPLES

 Los condicionales simples son operadores que nos permiten tomar decisiones
 entre las ejecuciones de los distintos comandos.

 El condicional mas simple es el operador &&. Cuando dos comandos son
 separados por este operador, el segundo comando se ejecutaro solo si el
 primero retorna un codigo de estado de salida igual a 0 (indicando una
 ejecucion exitosa).

 Este operador es util para indicarle a la shell que queremos ejecutar una
 secuencia de comandos, pero solo si se van ejecutando exitosamente. En
 caso de que alguno falle, los demas no se ejecutaran.

 En el capitulo 9 vimos que para compilar e instalar un programa debemos
 ejecutar una secuencia de comandos. Podemos automatizar estos procesos
 ejecutando los comandos de la siguiente forma:
       
  ==> ./configure && make && make install

 De esta forma, solo se construira el programa (make) si la configuracion
 (./configure) fue exitosa y solo se instalara (make install) si se construyo
 correctamente.
                              
 El operador opuesto a && es ||.

 Cuando dos comandos son separados por || el segundo comando se ejecutara
 solo si el primero finaliza retornando un codigo de salida distinto de 0.

 12.7.2 EL CONDICIONAL IF

 Los operadores && y || son utiles para crear sentencias condicionales muy
 simples. La shell tiene estructuras condicionales mas sofisticadas como
 puede ser el condicional if.

 La sintaxis de esta estructura es:

   if "listas de condiciones"
   then
       "listas de comandos"

   elif "listas de condiciones"

       "listas de comandos"
   else
        "listas de comandos"
   fi

 12.7.3 LOS LOOPS CONDICIONALES WHILE Y UNTIL

 Los loops condicionales nos permiten repetir un grupo de comandos.

 La sintaxis del condicional while es la siguiente:

  while "lista de condiciones"
     do "lista de comandos"
  done

 La sintaxis de until es la siguiente:

  until "lista de condiciones"
       do "lista de comandos"
  done

 12.7.4 LA SENTENCIA FOR

 La sentencia for nos permite ejecutar una lista de comandos repetidamente.
 Esta sentencia nos exige que le ingresemos uns lista de palabras y ejecuta
 la lista de comandos una vez para cada palabra. La forma general de la
 sentencia es la siguiente:

  for "nombre" in "palabra1" "palabra2" ...
  do
    "lista de comandos"
  done

 La sentencia for puede ser utilizada sin la palabra "in". De esta forma la
 lista de palabras automaticamente sera la lista de parametros posicionales.
 Vemos un ejemplo en la figura 12.8.

  # ls
  comandos    environ*     existe*    reverse*   rxvt-linux*
  # cat existe
  for archivo
  do
    if test -r $archivo
    then
       echo $archivo existe !!!
    else
       echo $archivo no existe !!!
    fi
  done
  # existe reverse comandos windows
  reverse existe !!!
  comandos existe !!!
  windows no existe !!!

    Figura 12.8: Utilizando la sentencia for con parametros posicionales.

 12.7.5 LA SENTENCIA CASE

 La sentencia case de la shell es una forma de elegir varios caminos de
 ejecucion basandose en una comparacion por pattern matching.

 Su forma general es la siguiente:

  case "word" in
      "pattern1") "lista de comandos" ;;
      "pattern2") "lista de comandos" ;;
      ...
  esac

 12.8 EVALUACION DE CONDICIONES - TEST

 El comando test es utilizado en los scripts para testear ciertas condiciones
 y determinar, por ejemplo, si los archivos o directorios existen, etc. Este
 comando, que viene integrado con la shell, puede ser utilizado para
 realizar tres tipos de tests:

  1. Puede testear los archivos para averiguar ciertas caracteristicas.

  2. Puede realizar comparaciones entre cadenas.

  3. Puede realizar comparaciones numericas.

 El comando indica el exito o el fracaso del test utilizando su codigo de
 estado de salida. La utilizacion de los crchetes es un sinonimo del comando
 test. Veamos un ejemplo de la utilizacion de test en la figura 12.9.

  # pwd
  /home/tony/linux
  # echo $HOME
  /home/tony
  # [ $HOME = 'pwd' ] || echo No estamos en casa ;(
  No estamos en casa ;(
  # cd ..
  # [ $HOME = 'pwd' ] || echo No estamos en casa ;(
  #

           Figura 12.9: Evaluando condiciones con tets.

 El set completo de opciones del comando test se muestra en la tabla 12.1.

  -------------------------------------------------------------------------
                               Test de archivos

  -b archivo                 Verdadero si el archivo existe y es un archivo
                             de dispositivo de bloque.
  -c archivo                 Verdadero si el archivo existe y es un archivo
                             de dispositivo de caracter.
  -d archivo                 Verdadero si el archivo existe y si es un
                             directorio.
  -e                         Verdadero si el archivo existe.
  -f                         Verdadero si el archivo existe y es un archivo
                             ordinario.
  -L archivo                 Verdadero si el archivo existe y es un link 
                             simbolico.
  -r archivo                 Verdadero si el archivo existe y es posible
                             leerlo.
  -s archivo                 Verdadero si el archivo existe y su longuitud
                             es nayor a cero.
  -w archivo                 Verdadero si el archivo existe y es posible
                             escribirlo.
  -x archivo                 Verdadero si el archivo existe y es ejecutable.
  archivo1 -nt archivo2      Verdadero si el archivo 1 es mas nuevo que el
                             archivo 2.
  archivo1 -ot archivo2      Verdadero si el archivo 1 es mas viejo que el
                             archivo 2.
  -------------------------------------------------------------------------
                          Comparaciones de cadenas

  -z string                  Verdadero si la longuitud de la cadena es 0. 
  string                     Verdadero si la longuitud de la cadenas es
                             mayor a 0.
  string1 = string2          Verdadero si las dos cadenas son iguales.
  string1 != string2         Verdadero si las dos cadenas son distintas.
  ------------------------------------------------------------------------
                          Comaparaciones numericas

  -eq                        Igualdad (equal)
  -ne                        Distintos (not equal)
  -gt                        Mayor que (greater than)
  -lt                        Menor que (less than)
  -ge                        Mayor o igual que (greater or equal)
  -le                        Menor o igual que (less or equal)
  ------------------------------------------------------------------------
                            Operaciones logicas

  !                         Not (no)
  -a                        And (y)
  -o                        Or (o)
  ------------------------------------------------------------------------

                  Tabla 12.1: Opciones del comando test.

 12.9 EVALUACION DE EXPRESIONES - EXPR

 El comando expr es un programa simple que realiza operaciones aritmeticas
 sobre enteros. La expresion a evaluar se provee en la linea de comandos y
 expr produce la salida en la salida estandar.

 Cada argumento de este comando deber ser un numero entero o un operador.
 Como la mayoria de los argumentos son simbolos utilizados por la shell, es
 necesario utilizar secuencias de escape.

 Vemos ejemplos simples de la utilizacion de expr en la figura 12.10.

  # expr 2 + 4
  6
  # expr 2 * 6
  expr: syntax error
  # expr 2 \* 6
  12
  # expr 4 / 2
  2
  # expr 5 - 4
  1

          Figura 12.10: Utilizando expr para evaluar expresiones.


  Bueno hasta aca hemos llegado por hoy, espero que les haya gustado y les
  cuento lo que veremos en la tercera y ultima entrega:

  Analizamos y vemos un poco el Booteo, inicializacion y la detencion del
  sistema (cap.13), tambien veremos como instalamos y configuramos los
  dispositivos (cap.14), hablaremos tambien de la administracion del
  sistema y de su seguridad (cap.15) y por ultimo veremos el sistema de
  ventanas X WIndows (cap.16).

   Bueno, nos vemos en la ultima entraga de este manual de Linux 5.0.
   Espero que les haya gustado esta entrega y les sirva de ayuda tambien.

               Created By Mr. Nuk3m ( mr_nukem@mixmail.com )


