Taller Practico
Taller Practico
E.A.N.
el sistema operativo
unix
POR
JULIO REY DE PEREA CAMPOS
DIPLOMADO EN INFORMÁTICA
UNIVERSIDAD DE ALMERÍA - ESPAÑA
Bloque 1: Estructura de UNIX. 2
TEMA 1. INTRODUCCIÓN.
CARACTERÍSTICAS GENERALES:
El sistema está escrito en un lenguaje de alto nivel, haciéndolo fácil de leer, comprender,
cambiar y mover a otras máquinas.
Tiene una interfaz con el usuario simple que tiene el poder de suministrar los servicios que
quiere el usuario.
Provee primitivas1 que permite la realización de programas complejos a partir de
programas más simples.
Usa un sistema de archivos jerárquico que permite un fácil mantenimiento y una
implementación eficiente.
Usa un formato para los archivos consistente, el flujo de bytes, haciendo que los programas
de aplicación sean fáciles de escribir.
Provee una simple y consistente interfaz con los dispositivos periféricos.
Es un sistema multiusuario y multitarea, cada usuario puede ejecutar varios procesos
simultáneamente.
1
Las primitivas son comandos o instrucciones básicas del sistema.
Bloque 1: Estructura de UNIX. 3
Oculta la arquitectura de la máquina del usuario, haciendo fácil el escribir programas que
corran en diferentes implementaciones hardware.
Además de que el sistema operativo y muchos de los programas y comandos están escritos en
lenguaje C, UNIX soporta otros lenguajes, incluyendo Fortran, Basic, Pascal, Ada, Cobol, Lisp y
Prolog. UNIX soporta cualquier lenguaje de programación que tenga un compilador o intérprete y
una interfaz con el sistema que permita transformar las peticiones del usuario de servicios del sistema
al conjunto estándar de peticiones usadas en el sistema UNIX
como X, ocasionó un cambio de los entornos de trabajo basados en caracteres a interfaces gráficas
con el usuario.
Hoy día, UNIX es un sistema muy diferente de lo que fue a principios de los años setenta. En
aquella época, el sistema representativo era un solo procesador que servía a un conjunto de
terminales de teletipo conectadas al procesador a través de líneas telefónicas directas o conmutadas.
El sistema representativo actual es una estación de trabajo con una pantalla de alta definición de
mapa de bits que opera con un sistema de ventanas y participa activamente en una extensa red de
computadores. En aquella época, UNIX era pequeño, sencillo y no comercial, destinado a un público
reducido y selecto. Ahora, UNIX es un producto comercial importante, grande, complicado, que se
utiliza en una amplia gama de aplicaciones, muchas veces por personas que no tienen experiencia de
programación
EL PAPEL DE C EN UNIX:
La mayor parte del sistema UNIX está escrito en C; es más, C se diseñó para apoyar a
UNIX. Las organizaciones con licencias de los programas fuente de UNIX pueden modificar el
comportamiento del sistema UNIX alterando y recompilando los programas fuente.
2
Las llamadas al sistema son utilizadas por los programas para pedir servicios al kernel.
Bloque 1: Estructura de UNIX. 5
En la figura 2.1 se describe la arquitectura a alto nivel del sistema UNIX. El hardware en el
centro del diagrama provee al sistema operativo con servicios básicos tales como interrupciones y
excepciones, niveles de ejecución (prioridades), administración de memoria, etc. El sistema operativo
interactúa directamente con el hardware, suministrando servicios a los programas y librándoles de la
idiosincrasia del hardware. El sistema operativo es denominado normalmente como sistema kernel, o
simplemente kernel. Como los programas son independientes del hardware que hay por debajo, es
fácil moverlos entre sistemas UNIX que corren en diferentes máquinas si los programas no hacen
referencia al hardware subyacente.
Otras aplicaciones
sh
nroff
who
cpp Kernel
a.out
comp
cc Hardware
date
as
wc
ld
vi grep
ed
Otras aplicaciones
Programas como el shell y editores mostrados en niveles exteriores interactúan con el kernel
por medio de un bien definido conjunto de llamadas al sistema. Las llamadas al sistema instruyen al
kernel para hacer varias operaciones para el programa llamador e intercambiar datos entre el kernel y
el programa. Muchos de los programas mostrados en la figura están disponibles en las
configuraciones estándar del sistema y son conocidos como comandos, pero los programas de usuario
pueden existir también en este nivel, indicado por el programa a.out, el nombre estándar para los
archivos ejecutables producidos por el compilador de C. Otros programas de aplicación pueden
construirse en el nivel más alto. Por ejemplo, el compilador de C, cc, está en el nivel más exterior de
la figura: invoca al preprocesador de C, al compilador de dos pasos, al ensamblador y al enlazador,
todos ellos programas de nivel inferior.
Bloque 1: Estructura de UNIX. 6
Los dos conceptos centrales en el modelo del sistema UNIX son los archivos y los procesos.
La figura 2.2 muestra un diagrama de bloques del kernel, mostrando varios módulos y las relaciones
entre ellos. En particular, se muestra el subsistema de archivos en la parte izquierda y el subsistema
de control de procesos en la parte derecha, los dos mayores componentes del kernel.
programas de usuario
librerías
Nivel de usuario
Nivel kernel
Comunicación
inter-proceso
Subsistema de archivos Subsistema
de control Planificador
carácter block
drivers de dispositivos
Nivel kernel
Nivel hardware
Hardware
La figura 2.2 muestra tres niveles: usuario, kernel y hardware. Las llamadas al sistema y las
librerías representan el borde entre los programas de usuario y el kernel. Las llamadas al sistema son
parecidas a las funciones en los programas en C y las librerías transforman estas funciones a las
primitivas necesarias para entrar en el sistema operativo. Los programas en lenguaje ensamblador
deben invocar a las llamadas al sistema directamente sin las librerías de las llamadas al sistema.
Las llamadas interactúan con el subsistema de archivos y con el subsistema de control de
procesos. El subsistema de archivos controla los archivos, asigna espacio a los archivos, administra
el espacio libre, controla el acceso a los archivos, etc. Los procesos interactúan con el subsistema de
archivos mediante un específico conjunto de llamadas al sistema.
El subsistema de archivos accede a los archivos de datos usando un mecanismo de buffer que
regula el flujo de datos entre el kernel y los dispositivos de almacenamiento secundario. El
mecanismo de buffer interactúa con los controladores de dispositivos de E/S de tipo bloque para
iniciar la transferencia de datos desde y hacia el kernel. Los controladores de dispositivos (device
drivers) son los módulos del kernel que controlan las operaciones con los dispositivos periféricos. El
subsistema de archivos además interactúa directamente con los controladores de dispositivos de E/S
de tipo carácter sin la intervención de un mecanismo de buffer.
El subsistema de control de procesos es el responsable de la sincronización de los procesos,
la comunicación entre procesos, administración de memoria principal y la planificación de procesos.
El subsistema de archivos y el subsistema de control de procesos interactúan cuando se carga un
archivo en memoria para su ejecución.
El módulo de administración de memoria controla la asignación de memoria. Si en algún
momento no hay suficiente memoria física para todos los procesos, el kernel los mueve entre la
memoria principal y la secundaria.
El módulo del planificador o scheduler asigna la CPU a los procesos. Planifica los procesos
para ser ejecutados por turno hasta que voluntariamente liberen la CPU mientras esperan un recurso
o hasta que el kernel los saca cuando su tiempo de ejecución supera el tiempo de cuantum.
Finalmente, el control del hardware es el responsable de las interrupciones y de las
comunicaciones con la máquina. Los dispositivos como los discos o terminales pueden interrumpir a
la CPU mientras un proceso se está ejecutando. Así, el kernel debe restablecer la ejecución del
proceso interrumpido después de servir a la interrupción.
Un administrador del sistema puede ajustar las características operativas del sistema
mediante la configuración del kernel. La configuración del kernel es la acción de decirle a éste, de que
tamaño deben ser las tablas que utiliza el UNIX para el manejo de sus recursos; dicho proceso se
hace mediante la modificación de un archivo de parámetros. Después se toma el kernel y se enlaza
con ciertas subrutinas y se genera un nuevo kernel con las nuevas entradas. Este proceso no queda
operativo hasta que no se inicie de nuevo el equipo. Esta configuración solamente la puede realizar el
administrador del sistema.
Por ejemplo, cuando se configura el kernel es el momento donde se determina el número de
archivos que se pueden encontrar abiertos, el número de procesos que se pueden estar ejecutando a
un mismo tiempo, y el tamaño de los buffers,…; todos estos recursos los maneja UNIX por medio de
tablas y listas. El tamaño de estas tablas es definido por el administrador del sistema, por
consiguiente este tamaño no se puede modificar en medio de la ejecución.
Cuando no se configura bien el kernel con una debida estructuración y se deja exceso de
espacio para tablas se está desperdiciando la memoria, quitándole espacio a los procesos, debido a
que tiene un kernel muy grande.
Bloque 1: Estructura de UNIX. 9
EL SISTEMA DE ARCHIVOS:
El sistema de archivos o file system es la forma en el que UNIX gestiona los archivos
existentes en el sistema. El sistema de archivos está caracterizado por:
El sistema de archivos está organizado como un árbol con un único nodo raíz llamado root
(se representa con “/”); cada nodo que no es hoja de la estructura del sistema de archivos es un
directorio de archivos. Cada archivo está identificado por un nombre de archivo. El nombre de
archivo viene dado por un nombre de camino o ruta (path name) que describe como localizarlo en la
jerarquía del sistema de archivos. Un nombre de camino es una secuencia de nombres de
componentes separados por caracteres “/”; una componente es una secuencia de caracteres que
identifica un archivo que está contenido en el componente precedente (directorio). Un camino
completo comienza con un carácter “/” y especifica un archivo que puede ser encontrado empezando
en el nodo raíz del sistema de archivos. Así, “/etc/passwd”, “/bin/who” y “/usr/src/cmd/who.c” son
caminos completos que identifican archivos en el árbol mostrado en la figura 3.1, pero “/bin/who” y
“/usr/src/date.c” no. Un camino no tiene porqué empezar desde el root ya que pueden ser
identificados de forma relativa al directorio actual o de trabajo de un proceso en ejecución, omitiendo
el carácter “/” inicial en la ruta.
cmd
date.c who.c
Por ejemplo, si nos encontramos en el directorio src, la ruta cmd/date.c identifica un archivo
existente en el árbol.
Bloque 1: Estructura de UNIX. 10
La representación interna de un archivo viene dado por un inodo, el cual contiene una
descripción del almacenamiento físico del archivo e información acerca del propietario del archivo,
permisos de acceso y tiempos de acceso. Será descrito más adelante. Todos los archivos tiene un
inodo, pero puede tener varios nombres, todos ellos accederían al mismo inodo. Cada nombre se
denomina enlace. Cuando un proceso referencia un archivo por su nombre, el kernel analiza el
nombre de archivo de cada componente, comprueba que el proceso tiene permiso para buscar los
directorios en la ruta y recupera el inodo correspondiente al archivo. Por ejemplo, si un proceso
realiza la llamada
open (“/fs2/mjb/rje/sourcefile”,1);
Bloque físico: Se define como la mínima unidad de lectura y escritura de un disco. También
se conoce como el sector de un disco. El tamaño estándar es de 512 bytes.
El bloque lógico es siempre igual o mayor que el bloque físico. Lo mínimo que el sistema
operativo UNIX asigna a un archivo es un bloque lógico, así se tenga un archivo con un tamaño real
menor al tamaño del bloque lógico.
Por ejemplo: si se define un bloque lógico de 1K, y se tiene un archivo que ocupa 1200 bytes,
entonces a este archivo le corresponderían dos bloques lógicos, pero si nos damos cuenta siempre se
va a tener una pérdida o desperdicio de memoria, al menos que el tamaño real del archivo sea
múltiplo del bloque lógico que se le asigne.
Los distintos sistemas de archivos tienen básicamente la misma estructura, que se muestra en
la figura 3.2, la cual está formada por cuatro partes fundamentales:
Como hemos visto anteriormente, los sistemas de archivos en UNIX utilizan una estructura
en disco, denominado inodo, para almacenar información sobre cada archivo. El contenido de un
inodo, mostrado en la figura 3.3, es el siguiente:
Modo
Cuenta de enlace
ID. de usuario
ID. de grupo
Tamaño del archivo
Direcciones
de bloque
Fecha de acceso
Fecha de modificación
Fecha de cambio de inodo
4
Estos números serán descritos más adelante.
Bloque 1: Estructura de UNIX. 13
Inodo
PD0
: : Datos
: PD : Datos
PD9
PIS PD : Datos
: Datos
PID :
PIS :
PIT : Datos
PD : Datos
: Datos
PD : Datos
PIS :
:
: : Datos
PID : PD : Datos
PIS
DIRECTORIOS:
Como hemos visto, los directorios son los archivos que proporcionan al sistema de archivos
su estructura jerárquica; ellos juegan un importante papel en la conversión de un nombre de archivo a
un número de inodo. Un directorio es un archivo cuyos datos son una secuencia de entradas, cada una
de ellas constituida por un número de inodo y el nombre de un archivo contenido en el directorio. Los
bloques de almacenamiento de los directorios en los primeros sistemas de archivos que se diseñaron
tienen el formato mostrado en la figura 3.5.
Cada entrada en el directorio ocupa 16 bytes; de los cuales, dos corresponden al número de
inodo y 14 al nombre del archivo. Como se puede observar, todo directorio comienza con dos
entradas como mínimo: un identifica al directorio actual (‘.’) y la otra al directorio padre (‘..’).
Existen otros sistemas de archivos que permiten nombres de archivos de hasta 255
caracteres, como es el caso de los sistemas de archivos ufs.
Programa de usuario
Dispositivo
Figura 3.6: Relación entre los programas de usuario y los dispositivos periféricos.
Todos los dispositivos en UNIX son tratados como archivos. Estos archivos especiales
(device special file), conocidos también como nodos de dispositivos (device nodes) constituyen el
medio de acceso a los dispositivos. Entre los dispositivos que aparecen se encuentran los dispositivos
de cinta, impresoras, particiones de disco y terminales. Básicamente existen dos tipos de archivos
especiales:
Archivos especiales tipo bloque: Se emplean para manejar dispositivos cuya unidad mínima
de tratamiento de información es el bloque.
Archivos especiales tipo carácter: Se emplean para dispositivos cuya unidad mínima de
tratamiento de información es el carácter. También se engloban dispositivos que utilizan un
tamaño distinto del bloque.
Estos archivos en realidad están vacíos. El sistema emplea dos números enteros,
denominados número principal o mayor (14 bits) y un número secundario o menor (18 bits) y
almacenados en el inodo del archivo, para acceder al dispositivo asociado.
El número principal identifica una clase de dispositivo (en realidad identifica al driver de
dicha clase como pueden ser terminales, impresoras, discos, etc.) y el número secundario identifica a
un elemento de dicha clase (un terminal específico, un disco concreto, ...).
Desde el punto de vista del acceso a un archivo, existen tres tipos de usuarios a los que se les
pueden dar o denegar permisos sobre un archivo:
La capacidad de un usuario para trabajar con archivos depende del tipo de acceso que tenga
a dicho archivo. Los accesos disponibles en UNIX son:
Para un archivo:
Para un directorio:
Permiso de lectura (r): Permite ver los nombres de los archivos de un directorio. Si se
quiere información detallada sobre dichos archivos el directorio
tiene que tener el permiso de ejecución para dicho usuario.
Permiso de escritura (w): Permite cambiar el contenido de dicho directorio; crear nuevos
archivos, suprimir los existentes (este último caso depende de los
permisos de escritura de los propios archivos).
Permiso de ejecución (x): Se debe de hablar más bien de permiso de búsqueda ya que permite
situarse en dicho directorio y según el resto de los permisos,
permitirá crear, borrar, modificar o copiar archivos.
Además de los permisos de acceso rwx para el propietario del archivo, grupo al que
pertenece el propietario y resto de usuarios, existen tres permisos especiales que afectan cuando se
emplea el archivo como programa ejecutable. Estos modos sólo se aplican a archivos ejecutables y
sólo el superusuario puede fijarlos. Estos son:
set-uid Permite fijar el identificador de usuario (valor octal 4000), e indica que cuando el
programa se ejecuta, el identificador de usuario pasa a ser el del propietario del
archivo.
set-gid Permite fijar el identificador de grupo (valor octal 2000), e indica que cuando el
programa se ejecuta, el identificador de grupo pasa a ser el del grupo propietario del
archivo.
sticky bit Se denomina “bit de adherencia”(valor octal 1000) y se aplica a programas que son
compartibles por muchos usuarios. Con el bit de adherencia se consigue que el
programa no abandone el espacio de intercambio (swap) aunque nadie lo esté
utilizando. Se suele aplicar a programas de uso intensivo para mejorar sus tiempos de
respuesta.
Los dos primero permisos son de utilidad para programas, como mail, que deben crear
archivos en directorios no necesariamente poseídos por la persona que ejecuta el programa.
Bloque 1: Estructura de UNIX. 16
TEMA 4: PROCESOS.
ENTORNO DE PROCESAMIENTO:
NIVELES DE EJECUCIÓN:
La ejecución de los procesos de usuario en UNIX está dividido en dos niveles: usuario y
kernel. Cuando un proceso ejecuta una llamada al sistema, el modo de ejecución del proceso cambia
del modo usuario a modo kernel: el sistema operativo ejecuta y atiende el servicio que el usuario
requiere, devolviendo un código de error si falla la llamada. Muchas arquitecturas (y sus sistemas
operativos) soportan más niveles que los dos descritos aquí, pero los dos niveles, usuario y kernel,
son suficientes para el sistema UNIX. Las diferencias entre los dos modos son:
Los procesos en modo usuario pueden acceder a sus propias instrucciones y datos pero no a
las instrucciones y datos del kernel (o las de otros procesos). Los procesos en modo kernel,
sin embargo, pueden acceder a las direcciones del kernel y de los usuarios.
Algunas instrucciones máquinas están privilegiadas y producen error cuando se ejecutan en
modo usuario.
ESTADOS DE UN PROCESO:
5
El proceso swapper se encarga de intercambiar procesos desde la memoria principal al área de swap y
viceversa
Bloque 1: Estructura de UNIX. 17
La figura 4.1 muestra un diagrama completo de los estados de los procesos y sus
transiciones. El proceso entra en el modelo de estados en el estado de “creación” cuando el proceso
padre ejecuta la llamada al sistema fork y eventualmente se mueve a un estado donde está listo para
correr (3 o 5). Por simplicidad, asumimos que el proceso entra en el estado “listo para correr en
memoria”. El proceso planificador o scheduler6 pondrá el proceso a ejecutar, y el proceso entra en el
estado “ejecución en modo kernel”, donde completará su parte de la llamada al sistema fork.
Cuando el proceso completa la llamada al sistema, se mueve al estado de “ejecución en modo
usuario”. Después de un periodo de tiempo, el reloj del sistema interrumpe el proceso y entra en el
estado de ejecución en modo kernel otra vez. Cuando la menejador de la interrupción del reloj termina
de servir la interrupción de reloj, el kernel decide planificar otro proceso a ejecutar, así el primer
proceso entra en el estado de “espera” y el otro proceso empieza a ejecutarse. El estado de “espera”
es realmente el mismo que el estado de “listo para correr en memoria”, pero están representados
separados para expresar que un proceso ejecutándose en el modo kernel puede ser pasado a modo
“espera” sólo cuando va a retornar a modo usuario. Consecuentemente, el kernel puede llevar al área
de swap un proceso en el estado de “espera” si es necesario. En cualquier momento, el scheduler
eligirá el proceso para volver a ejecución y retornará al estado de “ejecución en modo usuario” otra
vez.
Cuando un proceso ejecuta una llamada al sistema, deja el estado de “ejecución en modo
usuario” y entra en el estado de “ejecución en modo kernel”. Suponemos que el proceso realiza una
operación de E/S y debe esperar a que la operación se complete. Entra en el estado de “dormido en
memoria” quedándose bloqueado hasta que se le notifique que la operación de E/S esté completa.
Cuando la operación termina, el hardware interrumpe a la CPU y el manejador de interrupción
desbloquea el proceso, causando su entrada en el estado se “listo para correr en memoria”.
Supongamos que el sistema está ejecutando tantos procesos simultáneamente que no pueden
guardarse todos en memoria principal, y el proceso swapper guarda el proceso en el área de swap
para hacer sitio a otros procesos que están en el estado de “listo para correr guardado”. Cuando
desaloja la memoria principal, el proceso entra en el estado de “listo para correr guardado”.
Eventualmente, el swapper elige el proceso con mayor prioridad del área de swap y lo pasa a la
6
El proceso planificador o scheduler se encarga de planificar los procesos, es decir, es el encargado de elegir
el proceso que va a ser ejecutado a continuación por la CPU.
Bloque 1: Estructura de UNIX. 18
memoria principal. y el proceso regresa al estado de “listo para correr en memoria”. El scheduler
después eligirá el proceso y lo enviará al estado de “ejecución en modo kernel”.
Cuando un proceso termina, invoca la llamada al sistema exit, entra en el estado de
“ejecución en modo kernel” y, finalmente, en el estado “zombie”.
Ejecución en
modo usuario
1
llamada al sist.,
interrupción regreso
interrup., regreso de interrup. regreso al usuario
Zombie Ejecución en
exit modo kernel
9 2 7 Espera
poner en espera
bloquear replanificar
proceso
insuficiente memoria
6 5
Dormido en desbloquear
en área de swap Listo para
correr guardado
TIPOS DE USUARIO:
Para usar un sistema UNIX es necesario estar registrado como uno de sus usuarios. Cada
usuario tiene un nombre de ingreso al sistema, una contraseña y un área del sistema de archivos
reservada para almacenar sus archivos.
Básicamente, existen dos tipos de cuentas de usuarios:
Cuentas de usuarios ordinarios: Son las más comunes. Contienen la siguiente información:
- Un nombre de usuario (login).
- Una clave de acceso o palabra de paso (password).
- Un identificador de grupo.
- Un directorio personal (home directory, $HOME)
- Un shell de conexión o de ingreso (login shell).
Cuenta de superusuario: Cualquier sistema UNIX debe tener un superusuario. Es la
persona encargada de administrar el sistema; por ejemplo se encarga de crear nuevos
usuarios, configurar dispositivos, ... El superusuario tiene el nombre “root” como nombre
de usuario. Se identifica porque en pantalla aparece un prompt diferente al de un usuario
normal (normalmente el carácter “#”). El superusuario tiene acceso a todos los archivos y
directorios del sistema. En el bloque 3 se explicarán sus funciones.
GRUPOS:
Bloque 2: UNIX a nivel de usuario. 20
CONEXIÓN AL SISTEMA:
Para poder entrar en una cuenta aparece el llamado system login prompt:
eancol
eancol!login:
donde “eancol” es el nombre del host o hostname. Se introduce el nombre de usuario (también
conocido como login name, user id o account). A continuación se nos pedirá la palabra de paso o
clave de acceso:
Password:
From
DESCONEXIÓN:
Se utiliza cuando se termina el trabajo con UNIX. Se conoce como “logout” o “log off”. Se
realiza escribiendo logout o exit. En otros sistemas UNIX, también se puede mediante <Ctrl>-d (fin
de archivo).
Bloque 2: UNIX a nivel de usuario. 23
TEMA 3: EL SHELL.
¿QUÉ ES EL SHELL?:
exec shell
El shell Bourne, sh, escrito por Steve Bourne en 1979, es parte de la séptima edición de
UNIX y el primero de los shells principales. Los shells más nuevos son más sencillos de usar porque
ofrecen recursos de los que carecía el shell Bourne, como la edición de líneas de mandatos, la
recuperación de mandatos emitidos previamente y los alias para los mandatos de uso común. No
obstante, muchos usuarios de UNIX prefieren el shell Bourne para uso interactivo. Casi todos los
procedimientos de shell siguen los convencionalismos del shell Bourne.
Entre los recursos importantes que ofrece sh están los siguientes:
EL SHELL C (csh):
El shell C, disponible a través del mandato csh, se desarrolló como parte de BSD UNIX. A
pesar de su nombre, el shell C no es mucho más parecido a C que el shell Bourne. Algunas de las
características del shell C que no se incluyen en el shell Bourne son:
Varios de los mandatos en csh se comportan igual que sus contrapartes de sh.
El shell Korn, ksh, ofrece una síntesis de las características de los shell Bourne y C, además
de otras propias. Fue desarrollado por David Korn, de AT&T Bell Laboratories, en 1982,
presentando versiones mejoradas en 1986 y 1988. Se incluye como característica estándar de la
versión 4 de System V y otros sistemas; también se puede obtener por separado.
El shell Korn sigue de cerca los convencionalismos del shell Bourne, y casi todos los
procedimientos de shell escritos para el primero funcionan con el segundo. Las características
principales que se adoptaron del shell C son:
El shell tcsh es una versión mejorada del shell C que ha adquirido mucha
popularidad. Algunos de los recursos adicionales que ofrece son:
#! shell
donde shell es el nombre de la ruta completa del shell que se usa para interpretar el script. El espacio
en blanco después de “#!” es opcional. Por ejemplo, si se escribe un guión usando el conjunto de
mandatos del shell C, deberá comenzar con
#! /bin/csh
Algunos sistemas que no respetan el convencionalismo “#!” ofrecen otra manera de etiquetar
los procedimientos de shell: si el primer carácter es “:”, se considera como un script del shell Bourne;
si el primer carácter es “#”, se considera como un script del shell C.
Bloque 2: UNIX a nivel de usuario. 26
Una orden o comando es una secuencia de palabras por uno o más espacios en blanco.
Formato:
La primera palabra es la propia orden. El resto de las palabras son argumentos de la orden.
Estos son los argumentos de las órdenes:
Opción(es): Es un literal, normalmente precedido por el signo menos. Por ejemplo: -al. Una
opción modifica la acción de la orden de alguna manera o da detalles de cómo tiene que
funcionar exactamente.
Expresión: Describe una cadena de caracteres que se va a utilizar como entrada para la
orden.
NombreArchivo(s): Nombre de uno o más archivos que la orden va a manipular de alguna
manera.
Ejemplos:
rm -fi datos.txt fich.pas Borra dos archivos con las opciones “f” e “i”.
grep “Hola” saludo Busca patrones en un archivo donde el primer argumento es
una expresión y el segundo argumento es un nombre de archivo.
Si por alguna razón tiene que utilizar un argumento que contiene un espacio o bien tiene que
limitarlo, el argumento entero debería colocarse entre comillas dobles (“) o entre comillas simples o
apóstrofos.
METACARACTERES:
El shell reconoce como especiales una serie de caracteres, a los que se les denomina como
metacaracteres. Tienen varias aplicaciones, que a continuación se describen.
Caracteres comodines:
Estos caracteres se utilizan para sustituir una secuencia de caracteres. Entre los más
importantes están:
[x-y] Proporciona algún carácter dentro del rango x,y. Se pueden especificar varios rangos
o combinar rangos con caracteres. No hace falta ningún carácter separador.
Redireccionamiento de la E/S:
Estos caracteres se usan para cambiar la entrada estándar (que es el teclado) o la salida
estándar (que es el monitor). Son los siguientes:
> Redirecciona la salida hacia un archivo o dispositivo. Si el archivo existe, dará error.
>> Añade la salida a un archivo.
< Redirecciona la entrada de un archivo. Hay comandos que no aceptan el
redireccionamiento de entrada.
cmd << word
Indica que un comando o un programa, cmd, normalmente interactivo, acepta sus
órdenes desde el mismo archivo o dispositivo (usualmente un shell script). word se
interpreta literalmente como la marca de fin de entrada para el comando.
>& Salida de errores: Cuando se produce un error, se usa un canal diferente (que el de
salida) para informar del error. Se puede enviar los errores a otro archivo o
dispositivo.
‘’ Comillas simples: Es otra forma de redireccionar la salida. Se ejecuta primero lo que
se encuentra entre las comillas, y el resultado puede servir como argumento para
otro comando. Por ejemplo:
rm * No elimina los archivos ocultos.
rm ‘ls -a’ Elimina todos los archivos.
Pipe. Pipeline:
Un pipe consiste en usar la salida de una orden como entrada a otra orden. Se representa con
el carácter “|”. Un pipeline o interconexión es un conjunto de órdenes unidas por pipes. Por ejemplo:
ls /etc | wc
Muestra el número de líneas, palabras y caracteres del listado del directorio /etc.
Líneas multicomando:
Sintaxis:
cd [<dir>]
casos especiales:
cd ..
cd $HOME
cd $home
cd
El primer caso especial nos permite situamos en el directorio padre del directorio actual. Los
otros tres casos nos permite situarnos automáticamente en nuestro directorio de trabajo (home
directory).
Sintaxis:
pwd
Sintaxis:
mkdir <dir>
Sintaxis:
rmdir <dir>
Sintaxis:
mv <dir-antiguo> <dir-nuevo>
Sintaxis:
cp -R <dir-origen> <dir-destino>
Sintaxis:
ls [alFRxt] [<dir>]
Bloque 2: UNIX a nivel de usuario. 29
El comando "l" es equivalente a "ls -l". Significado de la descripción detallada de "ls -l":
…
drwxr-x--- 2 julio group 224 Jul 19 11:19 bin
drwxr-x--- 2 julio group 336 Jul 17 17:14 fuentes
- rw -r------ 1 julio group 24 Jul 25 15:57 cx
- rwxr-x--x 1 julio group 35 Jul 19 11:44 whiet
…
El primer campo es el modo del archivo. La primera columna nos indica el tipo de archivo
(- ordinario, d directorio, b archivo especial de bloque, c archivo especial de carácter, l
archivo simbólico, p archivo especial FIFO). El resto del campo nos dice cuáles son los
permisos del archivo.
Número de enlaces. Para archivos es normalmente 1. Si es mayor de 1 indica que existe
entradas en otros directorios apuntando a ese archivo. Para directorios, indica el número de
entradas de subdirectorios que contiene.
Nombre del propietario. Muestra el nombre del propietario del directorio o archivo.
Nombre del grupo del propietario.
Tamaño del archivo, en bytes. Para archivos de texto es el número de caracteres.
Fecha y hora de la última modificación.
Nombre del archivo.
Sintaxis:
file <filename>
Determina el tipo de un archivo examinando su contenido. Algunas de los posibles resultados son:
Sintaxis:
touch <filename>
more
Sintaxis:
more [<filename>]
Visualiza un archivo de texto pantalla a pantalla. Una vez que se esta ejecutando se puede hacer lo
siguiente:
Ejemplo:
% more /etc/passwd
cat
Sintaxis:
cat [<filename>…]
Permite visualizar el contenido de uno o más archivos sin paradas a través del dispositivo de salida
estándar. Se puede detener la imagen pulsando <Ctrl>-S, y para continuar <Ctrl>-Q. Ejemplo:
pg
Sintaxis:
pg [ - | + <número>] [+/<patrón>] <filename> …
Permite paginar la salida. Si el fichero a ver tiene más de 24 líneas, 'pg' visualizará las 23 primeras y
presentará en la línea 24 un carácter ':' de petición de orden:
% pg -20 archivo Fija el tamaño de pantalla en 20 líneas en lugar de las 24 que hay por
defecto.
% pg +13 archivo Comienza a visualizar a partir de la línea 13.
% pg +/patrón/ archivo Comienza a listar a partir de la 1ª línea que contenga 'patrón'.
tail
Sintaxis:
tail [ + I - <número>] <filename>
Permite examinar el final de un archivo. Por defecto visualizará las diez últimas líneas, pero es
posible modificar dicho número. Ejemplos:
% tail -3 /etc/passwd Visualiza las tres últimas líneas del archivo /etc/passwd.
% tail +10 /etc/group Visualiza el archivo a partir de la línea 10. Si se utiliza la opción
'+nº líneas', y el archivo no tiene tantas líneas, no se visualizará
nada.
head
Sintaxis:
head [ - <número>] <filename>
Nos permite visualizar las diez primeras líneas de un archivo, aunque como en el caso de tail
podemos modificar su valor. Ejemplo:
Sintaxis:
mv <filename1> <filename2>
ó
mv <filename>… <directory>
Ejemplos:
mv mensaje01 mesj.01 Cambia el nombre del archivo mensaje01; y en el caso de que
existiese mesj.01 éste cambiará su contenido por el de mensaje0l.
mv user10/mbox user11 Movemos el archivo 'mbox' del directorio user10 al directorio
userll.
Sintaxis:
cp <filename1> <filename2>
ó
cp <filename>… <directory>
Bloque 2: UNIX a nivel de usuario. 32
Ejemplo:
Después de haber realizado la copia de un archivo, el modo del archivo es el mismo que tenía el
original.
Sintaxis:
rm <filename> …
Permite borrar o suprime uno o más archivos de un directorio (sólo puede borrarlos el propietario o
el super usuario). En el caso de que uno de los archivos a suprimir estuviese protegido contra
escritura, 'rm' le informaría del modo real del archivo, y esperaría una respuesta: si pulsa 'y' procede
a borrarlo y si pulsa cualquier otra tecla no lo borrará. Opciones:
-i : (Interactiva). 'rm' pide confirmación de cada uno de los archivos que va a borrar,
independientemente de que esté o no protegido.
-f : Si se quiere forzar la supresión de archivos estén o no protegidos.
-r : Si se quiere borrar el contenido del directorio actual, y de los posibles subdirectorios
que existan a partir de é1 (recursivamente).
Sintaxis:
umask [<valor>]
donde <valor> es un valor en octal indicando los permisos del propietario, grupo y otros. que se van
inhabilitar cuando se cree un archivo. Normalmente es 022. El primer dígito indica los permisos del
propietario, el segundo los permisos del grupo y el tercero los permisos de otros. El permiso de
ejecución se indica con 1, el de escritura con 2 y el de lectura con 4. Para una combinación de estos
permisos, se suman esos valores. Ejemplo:
% umask 037
Los archivos que se creen tendrán inicialmente los permisos de rwx para el propietario, r-- para el
grupo y --- para el resto.
Sintaxis:
chown <username> <filename> …
Bloque 2: UNIX a nivel de usuario. 33
Cambia el propietario de un archivo o de un directorio. <username> pueden ser también el UID. Sólo
el propietario y el super usuario puede cambiar al propietario de un archivo.
Sintaxis:
chgrp <groupname> <filename> …
Permite cambiar la propiedad de grupo de directorios y archivos a otro grupo del sistema.
Sintaxis:
chmod modo archivo …
chmod cambia los permisos de un archivo o directorio donde el modo es [ugoa+-rwx]. Siendo:
u usuario/propietario
g grupo
o otros usuarios
a todos los usuarios (equivale a ugo)
+ da el permiso
- quita el permiso
rwx permisos de lectura, escritura y ejecución
Sólo puede ser cambiado por el propietario del archivo o por el superusuario. El modo se puede
especificar también en octal. Ejemplos:
IMPRESIÓN:
Sintaxis:
lp <filename>
El archivo se imprime en la impresora por defecto del sistema. Tras ejecutar la orden el sistema nos
indicará el número de solicitud de impresión o 'id-request'.
Sintaxis:
Bloque 2: UNIX a nivel de usuario. 34
cancel [<id-request>]
Tan sólo se puede cancelar las peticiones de impresión que haya efectuado un determinado usuario.
Ejemplo:
% cancel 65
ORDENES DIVERSAS:
Sintaxis:
passwd
Cambia la clave de acceso (palabra de paso) a una cuenta de usuario. Sólo el propietario de la cuenta
o el superusuario pueden cambiar un password.
Sintaxis:
who
ó
who am i
informa de quién esta conectado al sistema o de quién soy yo. Aparece la siguiente información:
Sintaxis:
clear
Sintaxis:
ln [-s] <filename>
Bloque 2: UNIX a nivel de usuario. 35
Enlace fijo: Es una entrada en un directorio estándar. Sólo se hacen a archivos existentes y
dentro del mismo file system al que pertenezca el archivo. Para eliminar un archivo, se tiene
que eliminar todos los enlaces fijos (incluyendo el primer nombre que se le dio al archivo).
Enlace simbólico: Se realiza con la opción -s. Es una entrada de directorio especial que
apunta a otro archivo existente. El archivo puede estar en otro file system. Si se elimina el
archivo al que apunta, no eliminan todos sus enlaces simbólicos.
PROCESOS:
Como hemos visto anteriormente, cualquier usuario puede ejecutar varios procesos al mismo tiempo,
uno en modo atendido o primer plano (foreground) y los demás en modo desatendido o segundo plano
(background). Cuando un proceso se ejecuta en background el resultado del proceso no se visualiza
en pantalla, siempre y cuando no utilice la E/S estándar. A partir de ese instante se puede introducir
nuevas órdenes mientras se ejecuta ese proceso en background.
Para colocar un proceso en background hay que terminar la línea de órdenes con el carácter '&'. El
sistema nos devolverá el PID (identificador de proceso) asociado al proceso en background.
Sintaxis:
ps
La orden ps (Processes Status) muestra los procesos que están en ejecución. Por ejemplo:
donde : PID es el identificador de proceso, TTY es el terminal de control donde se creó el proceso,
TIME es el tiempo de CPU usado por el proceso y COMMAND indica los procesos en ejecución.
Su sintaxis es:
kill [ - <código> ] <PID>
Para detener procesos ejecutándose en primer plano pulse la combinación de teclas <Ctrl>-Z (esto no
elimina el proceso, sólo lo detiene). Para eliminar la ejecución de un proceso en primer plano
(foreground), pulse <Ctrl>-C. Si desea eliminar (terminar su ejecución) un proceso background
concreto se necesita conocer su PID y a continuación ejecutar la orden kill. Si no es posible detener
un proceso con la orden kill <PID> , se tiene que utilizar el <código> 9, que corresponde a parada
segura. Los usuarios tan sólo podrán detener los procesos que les pertenezcan.
Bloque 2: UNIX a nivel de usuario. 36
Sintaxis:
at [<opciones>] <time> [<date>]
donde <time> estará formado por 1, 2 ó 4 dígitos. Si se usa 1 ó 2 dígitos, se considerará como la
hora. Con 4 dígitos, se considerará hora y minutos. Permite ejecutar una orden en un determinado
momento (en el tiempo). Los comandos los toma de la entrada estándar y los ejecuta en modo
background. La salida de los comandos, si no se redirecciona, se almacenará como un mensaje en la
utilidad mail. Ejemplo:
El shell de UNIX no es un caso típico dentro de los intérpretes de comandos: aunque permite
al usuario ejecutar comandos en la forma usual, por ser un lenguaje de programación, puede hacer
mucho más. Al usar el shell el usuario escribe siempre pequeños programas de una línea: una
interconexión es un programa. El shell trabaja así: se le programa constantemente, pero eso es tan
fácil y natural (una vez que uno está familiarizado con él) que uno no lo considera como
programación.
El shell hace algunas cosas como iterar, redireccionar E/S y expandir nombres de archivos,
por lo que ningún programa necesita hacer eso; y algo más importante: la aplicación de estos
recursos es uniforme en todos los programas. Otras características como los procedimientos de shell
y las interconexiones, son en realidad proporcionados por el kernel, pero el shell proporciona una
sintaxis natural para crearlos. Estos van más allá de la comodidad; sirven en realidad para
incrementar las capacidades del sistema.
Gran parte de la potencia y la comodidad del shell derivan del núcleo de UNIX que está
atrás; por ejemplo, aunque el shell arma las interconexiones, en realidad es el núcleo el que mueve los
datos a través de ellas. La forma en que el sistema maneja los archivos ejecutables hace posible
escribir procedimientos de shell de manera que se ejecuten exactamente como programas compilados.
El usuario no necesita estar enterado de que son archivos de comandos (no se invocan con un
comando especial). Asimismo, el shell mismo es un programa, como hemos visto, y no forma parte
del núcleo, por lo que puede adaptarse, extenderse y emplearse como cualquier otro programa. Esta
idea no es exclusiva de UNIX, pero es donde mejor a sido explotada.
Veremos ahora algunas de las posibilidades que nos ofrece el shell. El shell con el que vamos
a trabajar de aquí en adelante va ser con el C shell, csh.
Ahora veremos cómo crear nuevos comandos a partir de los viejos por medio de los
procedimientos de shell o shell scripts. Dada una serie de comandos que van a ser repetidos varias
veces, sería conveniente convertirla en un "nuevo" comando con un nombre propio, de manera que
pueda usarse como un comando normal. En concreto, supongamos que uno intenta contar usuarios
frecuentemente mediante la interconexión
% who | wc -1
% who
you tty2 Sep 28 07:51
rhh tty4 Sep 28 10:02
moh ttys Sep 28 09:38
ava tty6 Sep 28 10:17
% cat nu
who | wc -l
% csh <nu
4
%
La salida es la misma que la que seria si se hubiera tecleado who | wc -1 en la terminal. Una
vez más, al igual que muchos otros programas, shell toma su entrada de un archivo si se le da alguno
como argumento; se podría haber escrito
% csh nu
para obtener el mismo resultado. Pero es molesto tener que teclear "csh" en uno u otro caso: Es más
tardado y crea una distinción entre programas escritos en, digamos, C y otros que se escribieron
conectando programas con el shell. Por lo tanto, si un archivo es ejecutable y si contiene texto,
entonces shell supone que es un archivo de comandos de shell. Tal archivo se llama procedimiento de
shell o shell script (como hemos visto anteriormente). Lo único que debe hacerse es incluir una línea,
la primera del archivo, que contenga el carácter “#” para forzar que el subshell que se va a ejecutar
sea el csh (en caso contrario sería el sh, que es el que se ejecuta por defecto)7. Después se hace nu
ejecutable haciendo:
% chmod +x nu
% nu
En lo sucesivo los usuarios de nu no podrán saber, con sólo ejecutarlo, que el lector lo ha
obtenido de esta sencilla manera. La manera en que el shell realmente ejecuta nu es crear un nuevo
proceso de shell exactamente igual que si se hubiera tecleado
% csh nu
csh nu no es lo mismo que csh<nu ya que su entrada, estándar está conectada aún a la
terminal.
Existen otros comandos simples que el lector podría crear de esta manera para adaptar el
ambiente a su propio gusto.
Aunque nu es adecuado tal como se mostró, la mayoría de los programas en shell interpretan
argumentos, de manera que por ejemplo las opciones y nombres de archivos puedan especificarse
cuando el programa se está ejecutando.
7
También es válido el convencionalismo de BSD UNIX, comentado en el tema 3 de este mismo bloque.
Bloque 2: UNIX a nivel de usuario. 39
% cx nu
% chmod +x nu
Ya conocemos casi todo lo que se necesita para hacer esto. Necesitamos un archivo llamado
cx cuyo contenido sea
chmod +x archivo
Lo único nuevo que necesitamos saber es cómo indicar a cx cuál es el nombre del archivo,
puesto que éste será diferente cada vez que se ejecute cx.
Cuando shell ejecuta un archivo de comandos, cada ocurrencia de $1 se reemplaza por el
primer argumento, cada ocurrencia de $2 se reemplaza por el segundo argumento y así sucesivamente
hasta $9. El argumento $0 es el nombre del programa en ejecución (en cx, $0 es “cx"). En
consecuencia, si el archivo cx contiene
chmod +x $1
cuando el comando
% cx nu
% echo '# \
chmod +x $1' >cx Cree cx originalmente.
% csh cx cx Haga que cx sea ejecutable.
% echo echo Hi. there! >hola Haga un programa de prueba.
% hola Pruébelo.
hola: Permission denied
% cx hola Hágalo ejecutable.
% hola Inténtelo otra vez.
Hi , there! ¡Funciona!
%
¿Y si se deseara manejar más de un argumento, por ejemplo si hubiera que hacer que un
programa como cx manejara varios archivos al mismo tiempo? Un primer intento es poner nueve
argumentos en el programa en shell, como en
chmod +x $1 $2 $3 $4 $5 $6 $7 $8 $9
(¡Sólo hasta $9 debido a que la cadena $10 se analiza como "primer argumento, $1, seguido de un
0"!) Si el usuario de este shell script proporciona menos de nueve argumentos, los restantes serán
cadenas nulas; el efecto es que sólo los argumentos que fueron realmente tecleados son pasados a
chmod por el subshell. Así, esto funciona, pero obviamente no es limpio y falla si se dan más de
nueve argumentos.
Bloque 2: UNIX a nivel de usuario. 40
Previendo este problema, shell proporciona una abreviatura $* que significa "todos los
argumentos". La manera correcta de definir cx entonces es
chmod +x $*
Un pequeño cambio ilustra que `...` se interpreta dentro de las comillas “...”:
Como otro ejemplo, supóngase que se desea enviar correo a una lista de personas cuyos
nombres de inicio de sesión están en el archivo mailinglist. Una manera difícil de tratar esto es editar
mai1inglist para convertirlo en un comando de mail apropiado y presentarlo al shell, pero es mucho
más fácil hacer:
Esto ejecuta cat para producir la lista de nombres de usuarios y éstos se convierten en
argumentos para mai1. Cuando interpreta la salida en comillas inversas como argumentos, el shell
trata a las nueva-líneas como separadores de palabras, no como terminadores de la línea de
comandos.
El shell tiene variables, como las que hay en la mayoría de los lenguajes de programación, las
cuales en la jerga de shell se llaman a veces parámetros o variables de entorno. Las cadenas como $1
son parámetros posicionales (variables que contienen los argumentos para un procedimiento de shell).
El dígito indica la posición en la línea de comandos. Existen otras variables de entorno: PATH es la
lista de directorios en donde se buscan los comandos, HOME es el directorio de inicio de sesión del
usuario, etcétera. A diferencia de las variables en un lenguaje normal, los parámetros posicionales no
Bloque 2: UNIX a nivel de usuario. 41
pueden alterarse; aunque PATH es una variable cuyo valor es $PATH, no existe una variable 1 cuyo
valor sea $1. $1 no es más que una notación compacta del primer argumento.
Dejando a un lado los parámetros posicionales, las variables de entorno pueden crearse,
accederse y modificarse. Para asignar variables se usa el comando set, por ejemplo:
% set PATH=:/bin:/usr/bin
es una asignación que cambia la trayectoria de búsqueda. No debe haber espacios alrededor del signo
de igual, y el valor asignado debe ser una sola palabra, lo cual significa que debe delimitarse si
contiene metacaracteres de shell que no deben ser interpretados. El valor de una variable se extrae
anteponiendo a su nombre el carácter “$”:
No todas las variables son especiales para el shell. Se pueden crear nuevas asignándoles
valores. Tradicionalmente, las variables con significado especial se escriben con letras mayúsculas, y
los nombres ordinarios con letras minúsculas.
Uno de los usos más comunes de las variables es recordar cadenas largas, como trayectorias:
% pwd
/usr/you/bin
% set dir=`pwd` Recuerde donde estamos
% cd /usr/mary/bin Vaya a otra parte
% ... Trabaje un rato
% cd $dir Retorne
% pwd
/usr/you/bin
%
Cada shell tiene sus propias variables de entorno intrínsecas. Estas variables
contienen normalmente información acerca de cual es el home directory del usuario, el directorio
donde colocar su correo, la forma del prompt, parámetros propios del shell, etc... El comando de shell
set despliega los valores de todas las variables definidas por el usuario, además de que se utiliza para
asignar valores a las variables. Para ver sólo una o dos variables, echo es más apropiado. A
continuación se muestra un ejemplo de variables de entorno intrínsecas con el csh:
% set
LOGTTY /dev/tty02
_d ()
argv ()
cdspell
history20
home /home/julio
ignoreeof
noclobber
path (/bin /usr/bin /home/julio/bin .)
prompt %
shell /bin/csh
status 0
%
Bloque 2: UNIX a nivel de usuario. 42
% unset variable
El valor de una variable se asocia con el shell que la crea, y no se pasa automáticamente a
los hijos del shell.
Esto significa que un shell script no puede cambiar el valor de una variable, ya que el script
es ejecutado por un subshell:
Cuando se desea hacer el valor de una variable accesible en subshells, se debe definir la
variable con el comando setenv de shell. Pero no hay forma de exportar el valor de una variable de un
subshell a su padre. He aquí un ejemplo:
% setenv x Hola
% csh Nuevo shell
% echo $x
Hola x conocido en subshell
% setenv x Adios Cambie su valor
% echo $x
Adios
% exit Deje este shell
% Retorne al shell original
% echo $x
Hola x todavía es Hola
Las variables asignadas mediante setenv no se visualizan con set. Para ello se utiliza el
comando env. Existen algunas variables de este tipo que son creadas automáticamente al iniciarse la
sesión (puede ser modificado dentro del archivo .profile). A continuación se ve un conjunto de ellas:
HOME=/home/julio
Bloque 2: UNIX a nivel de usuario. 43
PATH=/bin:/usr/bin:/home/julio/bin:
LOGNAME=julio
TERM=ansi
HZ=100
TZ=colombia06
SHELL=/bin/csh
MAIL=/usr/spool/mail/julio
HUSHLOGIN=FALSE
Iterar con un conjunto de nombres de archivos es muy común, y para ello existe la
proposición foreach. La sintaxis es:
Por ejemplo, una proposición foreach para obtener nombres de archivos, uno por línea, es
simplemente
La "i" puede ser cualquier variable de shell, aunque el uso de i es tradicional. Obsérvese que
el valor de la variable se accede mediante $i, pero que la iteración foreach se refiere a la variable i.
Hemos usado * para obtener todos los archivos en el directorio de trabajo, pero puede usarse
cualquier otra lista de argumentos. Normalmente se desea hacer algo más interesante que
simplemente imprimir nombres de archivos. Una cosa que hacemos a menudo es comparar un
conjunto de archivos con versiones anteriores.
FILTROS:
Hay una gran familia de programas de UNIX que lee alguna entrada, realiza una
transformación y escribe alguna salida. Entre los ejemplos figuran grep y tail para seleccionar una
parte de la entrada, sort para ordenarla, wc para contarla y así sucesivamente. A esos programas se
les da el nombre de filtros. A continuación describiremos algunos de ellos:
La familia grep:
Examina los archivos nombrados o la entrada estándar e imprime cada línea que contenga un
caso del patrón. grep es de gran utilidad para encontrar ocurrencias de variables en programas o
palabras en documentos; también sirve para seleccionar partes de la salida de un programa:
La opción -n imprime números de línea, -v invierte el sentido de la prueba y -y hace que las
minúsculas en el patrón se acoplen con las letras mayúsculas o minúsculas en el archivo (las
mayúsculas siguen correspondiendo exclusivamente con las mayúsculas).
En todos los ejemplos que hemos visto hasta ahora, grep ha buscado cadenas ordinarias de
letras y números, pero en realidad maneja patrones mucho más complicados e interpreta expresiones
en un lenguaje sencillo para describir cadenas. Desde el punto de vista técnico, los patrones son una
forma ligeramente limitada de los especificadores de cadena llamados expresiones regulares. Las
expresiones regulares se especifican dando un significado especial a ciertos caracteres. Los
metacaracteres ^ y $ “anclan” el patrón al inicio (^) o al final ($) de la línea. Por ejemplo:
imprime las líneas que comienzan con From. Conviene encerrar los patrones de grep entre apóstrofos.
grep maneja rangos de caracteres en forma muy parecida a los de shell, de forma que [a-z]
concuerda con cualquier minúscula. Pero se dan algunas diferencias; si un rango de caracteres
comienza con el símbolo ^, el patrón se acopla con cualquier carácter excepto los del rango. Por
consiguiente, [^0-9] concuerda con cualquier carácter que no sea un dígito.
Un punto '.'se acopla con cualquier carácter. El operador de cerradura * se aplica al carácter
o metacarácter anteriores (incluyendo el rango de caracteres) en la expresión, y en conjunto
concuerdan con cualquier número de acoplamientos sucesivos del carácter o metacarácter. Por
ejemplo x* concuerda con una secuencia de x lo más larga posible, [a-zA-Z]* se acopla con una
cadena alfabética, .* reconoce cualquier cosa hasta una nueva-línea y .*x concuerda con cualquier
cosa hasta la última x en el renglón. La cerradura se aplica exclusivamente a un carácter, de modo
que xy* reconoce una x seguidas por varias y. Además, "cualquier número" incluye cero.
Con expresiones regulares, grep es un lenguaje de programación simple. Por ejemplo, para
seleccionar en un archivo con campos delimitados con dos puntos las líneas cuyo segundo campo esté
vacío sería:
El patrón es: comienzo de línea, cualquier número de caracteres que no sean dos puntos,
doble dos puntos.
grep es en realidad el más antiguo de una familia de programas, otros miembros de la cual se
llaman fgrep y egrep. Su comportamiento básico es igual, pero fgrep busca muchas cadenas literales
simultáneamente, mientras que egrep interpreta expresiones regulares verdaderas: lo mismo que grep
pero con un operador “o” y paréntesis para agrupar expresiones que se explican más adelante.
Tanto fgrep como egrep aceptan el parámetro -f para especificar un archivo del cual leer el
patrón. En este archivo, las nueva-líneas separan los patrones que deben buscarse en paralelo.
Bloque 2: UNIX a nivel de usuario. 45
Las expresiones regulares interpretadas por egrep son las mismas que en grep, con un par de
adiciones. Los paréntesis pueden utilizarse para agrupar, de manera que (xy)* concuerda con la
cadena vacía, xy, xyxy, xyxyxy y así sucesivamente. La barra vertical | es un operador "o"; today
| tomorrow se acopla con today o tomorrow, como lo hace to(day|morrow). Por último, hay otros dos
operadores de cerradura en egrep, + y ?. El patrón x+ reconoce una o más x, y x? reconoce cero o
una x pero no varias.
Otros filtros:
Esta sección tiene por objeto indicar al lector la existencia y posibilidad de un rico conjunto
de pequeños filtros que ofrece el sistema. Esta lista no pretende ser exhaustiva.
Empezaremos con sort, que es tal vez el más útil de todos estos filtros. Clasifica (ordena) su
entrada por renglones en orden ASCII. Aunque esto es lo que obviamente se hace por defecto, hay
otras muchas maneras en que uno podría querer clasificar los datos; sort trata de tenerlas en cuenta
proporcionando multitud de opciones. Por ejemplo, la opción -f vuelve equivalentes las mayúsculas y
minúsculas, eliminando con ello la distinción entre ellas. La opción -d (orden de diccionario) ignora
todos los caracteres menos la letras, dígitos y blancos en las comparaciones. Aunque las ordenaciones
alfabéticas son las más comunes, algunas veces se necesita hacer una comparación numérica. La
opción -n clasifica atendiendo al valor numérico y la opción -r invierte el sentido de cualquier
comparación. Por tanto:
sort normalmente clasifica un renglón entero, aunque se le puede indicar que dirija su
atención sólo a campos específicos. La notación +m significa que la comparación omite los primeros
m campos; +0 es el inicio de la línea. Así por ejemplo:
Otras opciones útiles de sort son: -o, que especifica un nombre de archivo para la salida
(puede ser uno de los archivos de entrada) y -u, que suprime todos los grupos de renglones, menos
uno, que sean idénticos en los campos de clasificación.
El comando uniq es lo que inspiró la opción -u de sort: excluye todos los grupos de renglones
adyacentes duplicados menos uno. El hecho de tener un programa especial para esta función le
permite hacer tareas no relacionadas con la ordenación. Por ejemplo uniq eliminará los renglones e
blanco múltiples, esté clasificada o no su entrada. Las opciones invocan maneras especiales de
procesar las duplicaciones: -d imprime sólo los renglones duplicados; -u imprime únicamente los que
son únicos (o sea, no duplicados); y -c cuenta el número de ocurrencia de cada renglón. Tiene la
siguiente estructura:
El comando comm para comparar archivos. Si tenemos dos archivos de entrada ordenadores,
f1 y f2, comm imprime tres columnas de salida: los renglones que ocurren sólo en f1, los que ocurren
tan sólo en f2 y los que ocurren en ambos archivos. Cualquiera de esas columnas puede suprimirse
por medio de una opción:
Bloque 2: UNIX a nivel de usuario. 46
% comm -12 f1 f2
imprime únicamente los renglones que se encuentran en ambos archivos (no imprime las columnas 1
y 2), y
% comm -23 f1 f2
imprime los que se hallan en el primer archivo pero no en el segundo (no imprime las columnas 2 y
3). Esto es útil al comparar directorios, y al comparar palabras con un diccionario.
El mandato cut extrae porciones específicas de cada línea de entrada. Las porciones se
pueden definir especificando las posiciones que ocupan los caracteres, o los campos que ocupan y el
carácter que delimita los campos. La forma del comando es:
% cut -c 2,5-8,14-
% cut -f 1,3-4 -d :
especifica que deben extraerse los campos 1, 3 y 4 de cada línea, usando “:” como carácter
delimitador.
Los archivos de archivo contienen las líneas que se unirán. Si no se especifican archivos, se
pegan las líneas de la entrada estándar. Otra opción de paste es -dlista que indica que se va a usar
circularmente los caracteres de lista como separadores. Por ejemplo, si se especifica -d,; y hay cuatro
archivos de entrada, una línea podría tener este aspecto: tweedledum,tweedledee;huevo,caer.
if (expresión )
then
comandos si la expresión es verdadera
else
comandos si la expresión es falsa
endif
o también:
% if (! -f prueba) \
echo El archivo prueba no existe.
endif
El shell proporciona otros dos operadores para combinar comandos, || y &&, que a menudo
resultan más compactos y adecuados que la proposición if. El operador || no tiene relación alguna con
las interconexiones; es un operador condicional que significa OR (disyunción). El comando a su
izquierda se ejecuta; si la condición de terminación es cero (éxito), el comando a la derecha de || se
ignora. Si el lado izquierdo devuelve no-cero (fracaso) el lado derecho se ejecuta y el valor de la
Bloque 2: UNIX a nivel de usuario. 48
El shell ofrece una proposición case, idónea para realizar una selección múltiple. Su formato
es el siguiente:
switch (palabra )
case patrón : comandos
breaksw
default: comandos
breaksw
endsw
La proposición switch compara la palabra con los patrones de arriba hacia abajo y ejecuta
los comandos asociados con el primer patrón que se reconozca, y solamente ése. Los patrones se
escriben utilizando las reglas para reconocimiento de patrones, un tanto generalizadas a partir de las
disponibles para identificación de nombres de archivo. Cada acción termina con breaksw. default
recoge las acciones a realizar si palabra no coincide con ningún patrón.
while (comando )
cuerpo del ciclo ejecutado a condición de que el comando devuelva
verdadero
end
El comando condicional que controla un while puede ser cualquier comando. Para dar un
ejemplo trivial mostramos un ciclo while para esperar a que alguien (mary, por ejemplo) inicie sesión:
El sleep, que hace una pausa de 60 segundos, siempre se ejecutará normalmente (a menos
que se le interrumpa) y, en consecuencia, devuelve “éxito”, de modo que el ciclo se verificará una vez
por minuto si mary ha iniciado sesión.
EL CICLO REPEAT:
Bloque 2: UNIX a nivel de usuario. 49
Con el ciclo repeat se puede especificar que un comando o grupo de comandos se ejecute un
número determinado de veces (similar al for del C). Tiene la siguiente forma:
Como ejemplo tenemos la siguiente estructura que sirve para escribir en pantalla varias veces
Hola:
PRÁCTICAS:
1. Calendario
2. Correo electrónico.
3. Fin de sesión.
2. Escribir un shell que despliegue por pantalla las tablas de multiplicar 1-9 con while.
4. Shell que despliegue por pantalla los subdirectorios del directorio de trabajo.
Bloque 2: UNIX a nivel de usuario. 50
INTRODUCCIÓN:
El editor visual vi fue desarrollado por Bill Joy como parte del proyecto BSD UNIX y se ha
adoptado como característica estándar de System V. vi es un editor de pantalla; siempre mantiene en
la pantalla la imagen de una porción del archivo que se edita. Para ello se requiere una terminal que
permita controlar la posición del cursor y colocar texto arbitrariamente en la pantalla. vi es en
realidad una extensión del editor de línea ex y por eso desde vi se puede acceder a comandos de ex.
Cuando se está modificando un archivo en realidad no se modifica directamente el archivo
original que se tiene en memoria secundaria. Esto se debe a que el archivo se copia primero en un
área de anotación temporal ("buffer") y los cambios que efectuamos se realizan en dicha memoria
temporal.
En un determinado momento sólo se puede visualizar en pantalla una porción del archivo que
se desea modificar. A esta porción se le llama ventana en el archivo. Dentro de la ventana se puede
mover el cursor para controlar dónde se van a hacer los cambios en el archivo.
La línea inferior de la pantalla es la línea de estado, que vi usa para los siguientes fines:
MODOS DE FUNCIONAMIENTO:
vi siempre estará en uno de tres modos: el modo comando, el modo de entrada o el modo de
línea de estado. El modo fundamental es el de mandatos, ya que los otros dos son en realidad
variaciones del modo comando..
El modo comando es el que se emplea para emitir comandos cortos. En este modo, vi trata
cada carácter que se teclea en la terminal como mandato para hacer algo o como parte de
un mandato; el carácter no se presenta en la terminal.
El modo de entrada o modo texto es el que se emplea para insertar texto en el buffer. En
este modo, vi trata como datos los caracteres que se teclean y los presenta en la terminal, en
donde se encuentra el cursor; además, avanza el cursor una posición a la derecha.
El modo de línea de estado o modo de última línea es el que se emplea para emitir mandatos
largos. vi presenta en la línea de estado los caracteres que se teclean en este modo. El editor
ejecuta el mandato cuando se pulsa <Return>.
Para pasar del modo comando al modo texto existe una serie de comandos (tales como a, i, o,
O, etc…, cada uno de los cuales hará una acción determinada). Para pasar del modo texto al modo
comando se pulsa la tecla <Esc>. Para introducir un comando en modo de línea de estado desde el
modo comando se empieza con el carácter ':'.
Bloque 2: UNIX a nivel de usuario. 51
Estas son algunas de las formas de cómo se puede entrar en el editor vi.:
Envío de mensajes:
mail es la utilidad de UNIX con la cual los usuarios pueden enviarse mensajes entre ellos.
Cuando un usuario entra en su cuenta se le notifica de la llegada de correo mediante el siguiente
mensaje:
% mail <username>
Subject: <Motivo de la comunicación>
donde:
Recepción de mensajes:
Para poder determinar los mensajes que otros usuarios nos han enviado, se escribe lo
siguiente:
Se muestra en pantalla todos los mensajes recibidos ordenados en orden inverso al de llegada;
es decir, el primer mensaje que se muestra es el último que se recibió. La información que aparece es:
La utilidad mail tiene su propio prompt (&) para distinguirlo del shell. Si no existen
mensajes, mail dará un mensaje de aviso y permanecerá en el shell.
Opciones de mail:
Dentro de mail se pueden ejecutar órdenes del shell. Para realizar esto, basta con preceder a
la orden con el signo de admiración ('!'). Ejemplo: !ls
La salida de mail se puede realizar de tres formas distintas:
- Pulsando <Ctrl>-d.
- Pulsando q (quit).
- Pulsando x (xit).
En este último caso se abandona mail sin "perder" los mensajes. En los dos primeros, se nos
muestra un mensaje indicando que los mensajes quedan almacenados en el directorio de trabajo del
usuario en un archivo llamado mbox.
Se puede enviar correo a varias personas a la vez indicando más de un nombre de usuario en
la línea de órdenes. Por ejemplo:
Bloque 2: UNIX a nivel de usuario. 55
Por otro lado, si tiene un mensaje largo que enviar, lo puede redactar en un editor de textos y
posteriormente lo puede enviar redirigiendo la entrada estándar. Por ejemplo:
LA ORDEN WRITE:
La orden write proporciona comunicación directa entre dos usuarios, mediante envío de
mensajes directamente a sus dispositivos terminales. Estos mensajes interrumpirán cualquier
visualización sobre el terminal del receptor. El comando write acepta el nombre de usuario como
parámetro, determina cual es el dispositivo terminal del usuario y enviará mensajes allí. Cuando el
mensaje haya sido transmitido, write acabará regresando al shell. La orden write devolverá un
mensaje de error si el usuario especificado no está conectado.
El comando write obtendrá el mensaje de su entrada estándar. Si el carácter ‘!’ se encuentra
al principio de una línea, write llama al shell para que ejecute el resto de la línea como un comando y
la salida es enviada al terminal.
Cuando alguien utiliza write, en el terminal de destino aparece una cabecera:
El destinatario debe a su vez escribe write para responder al mensaje y se entra en mode de
comunicación interactiva entre los dos usuarios. La comunicación terminará al pilsar <Ctrl>-d (fin de
archivo).
Los usuarios pueden desactivar esta clase de comunicación directa con sus terminales por
medio del comando mesg de esta forma:
% mesg n
Los mensajes pueden ser permitidos de nuevo especificando ‘y’ en vez de ‘n’. La orden mesg
funciona modificando los permisos del archivo de dispositivo asociado con un terminal. Si un usuario
ha declarado desactivados mensajes, write devolverá un mensaje de error diferente.
Con frecuencia, el acceso de write se descapacita cuando se dirige salida de alta calidad al
terminal, como ocurre en algunas tareas de impresión.
Bloque 2: UNIX a nivel de usuario. 56
El manual del usuario es la documentación oficial del sistema UNIX y ha sufrido tanto
desarrollo y modificaciones durante años como el propio software del sistema. Todas las órdenes,
argumentos de órdenes, bibliotecas de subrutinas, formatos de ficheros, utilidades y herramientas
están totalmente documentadas en el Manual de usuario y es casi la última autoridad en todas las
cuestiones referentes al sistema UNIX. La autoridad última, naturalmente, es la comprobación
empírica directa de un atributo del sistema sobre la propia máquina.
Desgraciadamente, aunque el Manual de usuario es un documento de referencia completo, no
es tan accesible como pudiera desearse. No es raro que varios usuarios o creadores de software se
enzarcen en una discusión acerca de una sentencia del Manual de usuario referente al significado o
implicación de una palabra o frase. Invariablemente el Manual de usuario está correcto, pero a veces
no es fácil de entender.
El Manual de usuario es un documento de referencia. Está diseñado para ser tan conciso
como es posible, con objeto de exponer el gran alcance del sistema UNIX en un formato que los
expertos y casi expertos puedan utilizar para encontrar cualquiera de los muchos detalles específicos
del sistema. Es muy difícil, si no imposible, aprender a utilizar el sistema a partir del Manual de
usuario, pero es igualmente imposible convertirse en un usuario experto sin el manual.
Originalmente, el Manual del usuario fue publicado como un único volumen pequeño que
incluía toda la información que había disponible para el sistema operativo en ese momento. El
documento original contenía ocho secciones principales, que aún hoy se conservan:
La sección 4 documenta la manera en que los datos están almacenados en los ficheros que el
sistema utiliza.
La sección 5 contiene información útil que no sería adecuada en otras secciones. Por ejemplo,
incluye una tabla de códigos de caracteres ASCII, comentarios sobre las variables de entorno,
descriptores de los códigos de caracteres específicos de cada país, una discusión de las
especificaciones de tabulador en terminales, y mucho más.
En la sección 6 se describen juegos. Algunos sistemas no incluyen esta sección si la
implementación no incluye juegos, pero el software adicional para juegos incluirá generalmente
documentación que debería ser archivada en la sección 6.
La sección 7 incluye los formatos de los archivo especiales que residen en el directorio /dev.
Este material es del máximo interés para los programadores que deseen utilizar estos archivos de
dispositivos especiales en sus programas. La sección 7 incluye discusiones de los formatos de disco y
cinta, las interfaces de redes de área local.
La sección 8, sobre procedimientos de mantenimiento, incluye procedimientos para arrancar
el sistema, diagnosticar fallo hardware y otros aspectos de bajo nivel de la administración del
sistema.
Muchas máquinas grandes incluyen el contenido entero del manual en-línea, incluyendo
generalmente las páginas de manual para software de instalación local junto con el Manual de
usuario estándar. El texto completo ocupa generalmente entre dos y tres megabytes, por lo que las
máquinas más pequeñas no siempre incluyen el manual en-línea.
Estas páginas del manual en-línea pueden ser visualizadas con la orden man, que escribe la
página de manual solicitada en la salida estándar. Esta orden se invoca con un argumento que
especifica la página del manual que se desea visualizar. Por ejemplo:
% man diff
visualizará la página del manual correspondiente a diff(1)8. Si existe una entrada bajo el nombre
especificado en más de una sección del manual, se visualizarán todas las páginas del manual, una
tras otra. Es posible redirigir la salida a un fichero o a una impresora para un examen más detenido.
Las páginas del manual están generalmente formateadas con nroff cuando se visualizan, por lo que la
orden man puede tardar un tiempo relativamente largo en generar la salida.
Para restringir la salida a una página de manual de una única sección de manual, se puede
dar un número de sección antes del nombre de la página. Así, la orden
% man 1 passwd
8
El número entre paréntesis indica la sección del manual al que pertenece la entrada especificada.
Bloque 3: Administración del sistema. 58
EL SUPERUSUARIO:
Como se comentó al principio del bloque anterior, existe un usuario especial. Este usuario es
el superusuario, cuyo nombre de usuario (login) es “root”, el que tiene poderes olímpicos sobre la
ejecución (y posible destrucción) del sistema. El superusuario no está restringido por ninguna de las
protecciones de que dispone el sistema: puede obtener cualquier fichero, puede cancelar cualquier
proceso. Hay algunas operaciones del sistema que sólo el superusuario puede realizar.
Existen varias formas para pasar a superusuario. Una forma de entrar es arrancar el sistema
en modo monousuario. Otra forma es entrar en la cuenta de superusuario como si de un usuario
normal se tratase, introduciendo el nombre de usuario root cuando aparece el mensaje login; después
se introduce su clave. Una última forma de entrar es estando en una cuenta de usuario normal,
introducir el comando su y después introducir la clave.
La principal tarea del superusuario es la administración del sistema UNIX.
La administración del sistema consiste básicamente en gestionar los recursos del sistema para
que se puedan utilizar de la forma más eficiente posible así como llevar control de los usuario
potenciales del sistema. Entrando más en detalle, las tareas de administración del sistema más
comunes son las siguientes:
Añadir usuarios.
Instalar software (como aplicaciones y actualizaciones del sistema operativo).
Instalar hardware (como tarjetas, impresoras, terminales y modems).
Mantener la seguridad e integridad del sistema y de la red.
Diagnosticar y arreglar problemas software y hardware cuando ocurran.
Comprobar el uso de los sistemas de archivos para asegurarse de que no estén llenos y
además controlar el uso indiscriminado de los mismos.
Mantener impresoras, modems y terminales remotos.
Bloque 3: Administración del sistema. 59
La carga inicial (booting) es el proceso que hay que realizar para echar a andar el sistema
cuando se conecta la computadora inicialmente o cuando lo reinicializa después de una detención.
El programa de carga inicial, llamado bootstrap, que se encuentra almacenado en el bloque
de arranque del sistema de archivos raíz. Este programa se encarga de traer a memoria un programa
más complejo, el cual se encarga de cargar, configurar e iniciar el sistema UNIX.
El proceso de arranque consta de tres pasos fundamentales:
El primer paso en el arranque del sistema es cargar el sistema operativo desde el disco duro
de la computadora.
Se enciende la computadora y ésta carga el bootstrap y muestra el siguiente mensaje:
Boot
:
Cada sistema de archivos que se quiera cargar y tenga errores, mostrará un mensaje similar.
Para trabajar sin problemas, el sistema operativo necesita reparar el sistema de archivos.
9
Si existe una partición de DOS, se puede cargar desde aquí introduciendo el comando dos detrás del
prompt ‘:’.
Bloque 3: Administración del sistema. 61
Para reparar el sistema de archivos, introduzca ‘y’. La utilidad fsck (que será explicada más
adelante) limpiará el sistema de archivos, reparando los archivos dañados o borrando los archivos
que no se hayan reparado.
Cuando la reparación se haya completado, el sistema preguntará por el modo de
funcionamiento.
Se debe elegir el modo de funcionamiento tan pronto como salga el siguiente mensaje:
Parar un sistema UNIX requiere algo más que apagar la computadora ya que hay que
realizar una serie de pasos para preparar al sistema para la parada. El procedimiento exacto varía
dependiendo de la configuración. Un procedimiento típico podría ser parecido al siguiente.
Enviar mensajes de aviso a todos los usuarios presentes informando que el sistema va a ser
desconectado próximamente.
Cancelar (kill) todos los procesos en ejecución excepto el proceso de la consola.
Desmontar los sistemas de archivos.
Utilizar la orden sync para asegurar que toda la actividad de entrada-salida con el sistema
de archivos se ha terminado.
Apagar el computador si es necesario.
Existen dos comandos para parar el sistema: el comando shutdown o (bajo ciertas
condiciones) el comando haltsys.
El comando shutdown es la forma normal de para el sistema y debe ser usada cuando el
sistema s encuentra en modo multiusuario. El mismo avisa automáticamente a los usuarios mediante
el siguiente mensaje:
Esperará unos segundos, para dar tiempo a los usuarios a desconectarse, y pedirá
confirmación para la parada del sistema. Después cerrará todas las cuentas y cancelará todos los
servicios del sistema. Sólo se podrá apagar el sistema cuando aparezca el siguiente mensaje:
Usando el comando shutdown con la opción -gn, el proceso de parada comenzará después de
n minutos.
El comando haltsys para el sistema inmediatamente. El comando debe usarse sólo cuando se
está trabajando en modo monousuario. Si hay usuarios conectados cuando se ejecuta haltsys, se
terminará su sesión y perderán los trabajos que estaban haciendo. Además, los servidores de red así
como otros programas son terminados anormalmente y pueden crear problemas cuando rearranquen.
Al igual que el comando shutdown, no se debe desconectar la máquina hasta que no aparezca
el mensaje:
donde dispositivo indica el archivo especial asociado con el sistema de archivos que se va a montar y
directorio es el punto de montaje. Con la opción -r se indica que el sistema de archivos será de sólo
lectura. Con la opción -f se especifica el tipo de sistema de archivos que se va ha instalar. Si se omite
esta opción, se toma por defecto el mismo tipo que el del sistema de archivos raíz. Esto son los
sistemas de archivos disponibles:
umount dispositivo
Al construir un sistema de archivos nuevo, hay que especificar el número de bloques que
contiene. El comando mkfs utiliza ese número para determinar el número de bloques que reservará
para inodos. Por ejemplo, supongamos que tenemos un dispositivo sobre disco flexible llamado
Bloque 3: Administración del sistema. 64
/dev/fd0. Supongamos además que ese disco flexible puede contener un máximo de 2000 bloques.
Construiremos un sistema de ficheros sobre este dispositivo así:
A continuación, sólo queda montar el sistema de archivos creado con la orden mount.
Veamos a continuación las órdenes df, que nos permite determinar el grado de ocupación de
los sistemas de archivos; du, que determina el tamaño de los archivos y directorios; y quot, que nos
muestra el número de bloques utilizado por cada usuario.
La orden df:
df [-vi] [<filesystem>]
Ejemplo:
Muestra los siguientes campos: punto de montaje, dispositivo asociado, bloques (de 1024
bytes) libres, inodos libres. Un sistema de archivos no podrá llenarse completamente. Esto es así
porque el sistema reserva una fracción del espacio en el sistema de archivos para permitir trabajar
bien a las rutinas de asignación en el sistema de archivos. La cantidad reservada es normalmente un
10%. Cuando todo el espacio disponible está usado (excepto el área de reserva), sólo el superusuario
podrá crear nuevos archivos y/o asignar bloques de datos a los archivos existentes.
La opción -i informa del número de inodos totales, usados y libres. La opción -v muestra los
bloques totales, los usados, los libres y el porcentaje de bloques usados.
La orden du:
La orden quot:
quot muestra el número de bloques (de 1024 bytes) que pertenece a cada usuario del sistema
de archivos especificado. Si no se especifica ninguno, se revisan todos los sistemas de archivos
montados. Su sintaxis es como sigue:
Bloque 3: Administración del sistema. 66
Con la opción -f se nos muestra el número de archivos y el espacio que ocupan para cada
usuario.
Este comando sólo lo puede usar el superusuario.
Existen dos aspectos del sistema que degradan la eficiencia de los sistema de archivos:
1. Fragmentación del disco: Cuando el archivo ha sido utilizado durante algún tiempo, la
constante creación y borrado de archivos producen una fragmentación en el disco, la cual
consiste en que los archivos son creados en varios pequeños pedazos en el disco duro. Es
posible recuperar parte del disco (5 al 10%) realizando un backup de los archivos,
removiéndolos y volviéndolos a restaurar.
2. Directorios muy grandes que incrementan el tiempo de búsqueda de un archivo: Se deben
evitar los directorios más grandes de lo necesario. Se debe tener presente algunas
limitaciones con respecto a tamaños. Un directorio que contenga hasta 30 entradas
además de las entradas . y .. encaja en un bloque único del disco y es fácil de accesar. Un
directorio puede tener hasta 286 entradas, y aún es aceptable si contiene solamente datos
almacenados. Más entradas en un directorio de trabajo constituyen un desastre.
Bloque 3: Administración del sistema. 67
Cada usuario que accede al sistema debe tener una cuenta de usuario (user account). El
archivo que contiene información sobre cada cuenta del sistema y de los usuarios que pueden
conectarse localmente a la máquina es el /etc/passwd. Las claves de acceso se almacenan en el
archivo /etc/shadow. Si este archivo no existe, se almacenarán en el /etc/passwd. El archivo
/etc/group almacena información acerca de los grupos de usuario existentes en el sistema.
El archivo /etc/passwd:
Contiene información sobre cada cuenta de usuario. Veamos un ejemplo de este archivo:
root:x:0:1:Superuser:/root:/bin/csh
daemon:x:1:1:System daemons:/etc:
bin:x:2:2:Owner of system commands:/bin:
sys:x:3:3:Owner of system files:/usr/sys:
adm:x:4:4:System accounting:/usr/adm:
uucp:x:5:5:UUCP administrator:/usr/lib/uucp:
nuucp:x:6:5:Anonymous UUCP site:/usr/spool/uucplogins/nuucp:/usr/lib/uucp/uucico
auth:x:7:21:Authentication administrator:/tcb/files/auth:
asg:x:8:8:Assignable devices:/usr/tmp:
cron:x:9:16:Cron daemon:/usr/spool/cron:
sysinfo:x:11:11:System information:/usr/bin:
dos:x:16:11:DOS device:/tmp:
mmdf:x:17:22:MMDF administrator:/usr/mmdf:
network:x:18:10:MICNET administrator:/usr/network:
nouser:x:28:28:Network user with no access privileges:/:/bin/false
listen:x:37:4:Network daemons:/usr/net/nls:
lp:x:71:18:Printer administrator:/usr/spool/lp:
audit:x:79:17:Audit administrator:/tcb/files/audit:
ingres:x:777:50:Database administrator:/usr/ingres:
games:x:42:50:Games Admin:/usr/games:/bin/rsh
julio:x:200:50:Julio Rey de Perea Campos:/home/julio:/bin/csh
german:x:201:50:G . M. C.:/home/german:/bin/csh
pepe:x:202:50:Cuenta de prueba.:/home/pepe:/bin/csh
En este archivo se tendrá una entrada por cada cuenta que exista en el sistema conteniendo
información de la siguiente forma:
username:password:uid:gid:comentario:directorio:shell
El archivo /etc/shadow:
root:jKemQiEWZNFic:9316:0:0
daemon:*::0:0
bin:*::0:0
sys:*::0:0
adm:*::0:0
uucp:*::0:0
nuucp:*::0:0
auth:*::0:0
asg:*LK**::0:0
cron:*::0:0
sysinfo:*::0:0
dos:*::0:0
mmdf:*::0:0
network:*::0:0
nouser:*:::
listen:*:::
lp:*::0:0
audit:*::0:0
ingres:*:7203:0:0
games:VQUevOs9/vJ/6iLntz0/OgMs:9318::
julio:wj214lv7C9hB2dT5UmNw6qTc:9316::
german:6KduXOtNpTNis:9316::
pepe:FsOWRXGNYqry.:9325::
En este archivo se tendrá una entrada por cada cuenta que exista en el sistema conteniendo
información de la siguiente forma:
username:password:ultcambio:minimo:maximo
password Clave encriptada de la cuenta. Tendrá como prefijo la cadena “*LK*” cuando la
cuenta está bloqueada, o la cadena “*RETIRED*” cuando la cuenta está siendo
retirada. Estará vacío este campo cuando la cuenta no posea password.
ultcambio El número de días desde el 1 de Enero de 1970, y la fecha del último cambio en el
password.
minimo El número mínimo de días requerido entre cambios de password.
maximoEl número máximo de días en los cuales el password es válido.
El archivo /etc/group:
La base de datos que almacena información sobre todos los grupos del sistema es el
archivo /etc/group. Un ejemplo de este archivo es el siguiente:
root::0:
other::1:root,daemon
bin::2:bin,daemon
sys::3:bin,sys,adm
adm::4:adm,daemon,listen
uucp::5:uucp,nuucp
mail::7:
asg::8:asg
network::10:network
sysinfo::11:sysinfo,dos
daemon::12:daemon
terminal::15:
cron::16:cron
audit::17:audit
lp::18:lp
backup::19:
mem::20:
auth::21:auth
mmdf::22:mmdf
sysadmin::23:
nogroup::28:nouser
group::50:ingres,julio,german,pepe
groupname:password:gid:listausuarios
siendo:
Con la utilidad administrativa sysadmsh se pueden realizar estas operaciones siguiendo una
serie de menús. Sin embargo, vamos a ver como crear cuentas de usuario, como borrarlas o
modificarlas de forma “manual”.
Para crear una cuenta de usuario se deben seguir esta serie de pasos:
1. Crear una entrada con el nuevo usuario en el archivo /etc/passwd, asignándole un nombre
de usuario (login name), un identificador de usuario no usado, un identificador de grupo,
un directorio de trabajo (home directory) y un shell de conexión.
2. Añadir el usuario a su grupo en el archivo /etc/group.
3. Crear el directorio de trabajo.
4. Copiar los archivos de arranque correspondientes al shell de ingreso que se le haya
asignado al usuario. Estos archivos se encuentran en los directorios ubicados en
/usr/lib/mkuser.
5. Cambiar el propietario y el grupo del directorio de trabajo y de los archivos creados en él
y asignárselo al usuario nuevo.
6. Crear password para la nueva cuenta.
1. Usar el comando rmuser usuario para borrar al usuario de las bases de datos.
2. Borrar el directorio de trabajo del antiguo usuario y todos los archivos creados por él.
Bloque 3: Administración del sistema. 71
CREACIÓN/BORRADO DE GRUPOS:
La orden finger, sin especificar un nombre de usuario, muestra información sobre cada
usuario que está conectado. Su sintaxis es:
Opciones:
TEMA 5. DISPOSITIVOS.
CREACIÓN DE DISPOSITIVOS:
Como hemos visto en el bloque 1, el sistema UNIX trata a todos los dispositivos como
archivos. Estos archivos están vacíos y únicamente contienen dos números, el número principal y el
número secundario. El número principal identifica el tipo de dispositivo y el secundario identifica a
un dispositivo concreto de ese tipo. También vimos que existen dos tipos de archivos especiales: tipo
bloque y tipo carácter.
La orden mkdev permite crear archivos especiales asociados a dispositivos periféricos en
caso de pérdida accidental o inexistencia de uno de ellos. Su sintaxis es la siguiente:
Esto es sólo un ejemplo de los posibles dispositivos que pueden crearse, existen más, como:
cintas, puertos serie, puertos paralelo, terminales, …
Bloque 3: Administración del sistema. 73
COMUNICACIÓN:
Frame Gruond 1 3
Transmit Data 2 2
Receive Data 3 8
Clear to Send 4 7
Request to Send 5 7
Data set ready 6 6
Signal Ground 7 5
Data Carrier Detect 8 1
Data Terminal Ready 20 4
Ring Indicator 22 9
DTE - Data Terminal Equipment: Como por ejemplo los dispositivos seriales de los
computadores y terminales.
DCE - Data Communication Equipment: Como los modems y algunas impresoras seriales.
La configuración de los dos tipos con respecto a pines es la misma. La única variación
consiste en que lo que en el DCE es entrada, en el DTE es salida.
DTE DTE
1 1
2 3
3 2
4 5
5 4
6 20
7 7
20 6
DTE DTE
1 1
2 2
Bloque 3: Administración del sistema. 74
3 3
4 4
5 5
6 6
7 7
20 20
Los dispositivos seriales utilizan para su comunicación dos tipos de protocolo: XON y XOF.
/etc/inittab:
Este archivo es leído por /etc/init, que es el proceso que atiende los dispositivos seriales. Este
archivo se lee cuando:
a) Se arranca el sistema.
b) Se termina un proceso de arranque (el usuario sale del sistema).
c) El administrador del sistema lo manda a ejecutar.
Al modificar los parámetros del archivo, los parámetros son temporales. Si se quiere hacerlos
permanentes, se deben hacer tanto en /etc/inittab, en los archivos del directorio /etc/conf/init.d o en
/etc/conf/cf.d/init.base, los cuales son la base para la generación del archivo.
init.base:
Su estructura es la siguiente:
Lo primero que hace el sistema es ejecutar el comando bcheckrc, el cual es un script que
evalúa el estado del sistema de archivos root, mediante el comando fsck. Después se asignan los
diferentes comandos que se ejecutan en el momento de iniciar el sistema. Su modo default es
monousuario, definido en la línea initdefault.
El archivo /etc/brc borra la antigua tabla del sistema de archivos que se encontraba en el
sistema de archivos en caso de que haya sido mal apagado.
/etc/ttytype:
Este archivo define el tipo de terminal que se asignará a cada dispositivo del sistema. Cuando
un usuario entra al sistema, el sistema busca que tipo de terminal se está utilizando, y lee sus
características de este archivo. En XENIX lee del archivo /etc/termcap. Luego las sitúa en la variable
TERMCAP. En cada archivo de arranque de los usuarios se hace una evaluación del tipo de terminal
Bloque 3: Administración del sistema. 77
en el cual está trabajando y se asume como ansi la terminal por defecto. Dado el caso que no se
quiera realizar la evaluación para que no haya necesidad de que el usuario escriba el tipo de terminal,
se puede suprimir esta línea del archivo, pero debe definirse entonces correctamente en el archivo.
Su estructura es:
ansi tty01
ansi tty02
ansi tty03
ansi tty04
: :
wy60 tty1a
wy60 tty2a
wy60 ttyi00
El proceso de evaluación lee el tipo de terminal para dicho dispositivo y como tal lo maneja.
Estos archivos contienen las secuencias de manejo de un gran número de terminales que
trabajan bajo UNIX/XENIX. XENIX utiliza el archivo termcap por defecto, UNIX utiliza terminfo.
Cada parámetro define una característica de la terminal, como número de líneas y columnas, blink y
video inverso.
Cada entrada en la base de datos, consiste de diferentes líneas que definen el tipo de terminal
y el control de caracteres de secuencias que manipulan el despliegue. El archivo /etc/termcap es un
archivo tipo ascii que puede ser editado. En las versiones de UNIX System V y versiones posteriores
se utilizan archivos que se encuentran bajo el directorio /usr/lib/terminfo/* para el control de las
terminales.
Por lo tanto, el archivo terminfo no puede ser editado, primero se debe editar el archivo
terminfo.src o un archivo en el que se guarden las descripciones para las terminales, y posteriormente
se debe compilar con el comando tic. Una vez compilado, el tic coloca los archivos en cada
directorio.
/etc/gettydefs:
Contiene las definiciones para comunicarse con los puertos. Cada definición tiene un prefijo
que corresponde al valor dado en /etc/ttys (XENIX) o en /etc/inittab (UNIX), y a continuación se
tienen los parámetros bajo los cuales va a trabajar el dispositivo, como velocidad, echo, número de
bits, entre otros. Contienen dos tipos de entrada:
Por ejemplo:
m#etiq.ini#condi.ini.#Condi.fin.#Desp.ini.#Eti.Fin.#Programa
mkdev parallel
Tenemos las opciones de añadir un puerto paralelo, eliminar un puerto paralelo, mostrar
información sobre configuración y pedir ayuda. Eligiremos la opción 1 y entonces aparecerá otro
menú, preguntando por el tipo de puerto paralelo que queremos crear:
Elegimos el puerto que queremos y nos preguntará a continuación por el IRQ con el siguiente
mensaje:
mkdev lp
nombre Nombre que queremos que tenga la impresora dentro del sistema.
comentario Nombre completo de la impresora o cualquier comentario que se
quiera hacer sobre la misma.
Bloque 3: Administración del sistema. 80
nombre de clase Nombre del grupo al que se quiere añadir la impresora. Las
impresoras que se vayan configurando se pueden agrupar siguiendo
cualquier criterio.
usar interfaz de impresora Se especifica el nombre de la interfaz que va a usar la impresora.
conexión Tipo de conexión de la impresora. Puede ser directa (local) o de
llamada (en red).
dispositivo El archivo del dispositivo que va a utilizar la impresora (por
ejemplo /dev/lp0).
banner Se pregunta si se desea el servicio de banner en la impresora.
Si se quiere colocar esta impresora como la impresora por defecto, se elige la opción
Configure, después la opción Default y por último se especifica el nombre de la impresora.
Para terminar de configurar la impresora hay que realizar las siguientes acciones, dentro del
menú Schedule de la opción Configure:
Con todo esto queda ya creada una impresora. Los usuarios pueden usarla mediante el
comando lp explicado en el bloque 2.
Bloque 3: Administración del sistema. 81
INTRODUCCIÓN:
Las copias de seguridad son una de las tareas más usuales y necesarias a realizar en el
mantenimiento de todo el sistema. El objetivo de toda copia de seguridad es el de poder recuperar
toda la información en caso de que ésta se pierda, por ello, es aconsejable que se realicen con una
cierta periodicidad y planificación. Por ejemplo, sería deseable que se hicieran copias diarias de
aquellos directorios que contienen los datos de los usuarios.
Existen varios tipos de copia de seguridad:
Copias imágenes:
Se copia toda la información de un sistema de archivos conservando toda su organización.
Cuando se realiza una recuperación, el sistema de archivos quedará tal y como estaba
cuando se realizó la copia. La recuperación de una copia imagen sólo se puede realizar
sobre un disco o partición de disco del mismo tamaño que aquél del que se realizó la copia.
Este tipo de copias de seguridad no es el utilizado en el trabajo diario. Pueden ser
convenientes realizarlas tras el proceso de instalación y/o cuando el sistema se encuentra en
un estado óptimo (bien configurado).
Copias incrementales:
Las copias incrementales consisten en realizar una copia completa periódicamente (una vez a
la semana o al mes) y diariamente, se hace una copia de los archivos que han sido
modificados desde la última vez que se realizó la copia de seguridad. Se necesita conocer
las fechas de grabación para cada archivo. Las copias incrementales no conservan la
organización del disco. La recuperación se podría realizar en cualquier parte. Es
recomendable que las copias incrementales se realicen con el sistema trabajando en modo
monousuario. Se deben considerar los siguientes elementos cuando se planifica una
estrategia de copias de seguridad:
Sistemas de archivos que necesitan que se les haga copias de seguridad.
seguridad.
Copias específicas:
Cuando se realizan copias de seguridad de los archivos que el operador desea guardar sin
tener en cuenta la fecha de modificación u otro criterio.
La orden backup:
Bloque 3: Administración del sistema. 82
La orden backup realiza copias de seguridad incrementales, de los archivos del home
directory de un usuario especificado, o de un conjunto de archivos y directorios determinados. Las
copias son restauradas con la orden restore. Su sintaxis es la siguiente:
La orden restore:
-c Realiza una completa restauración. Todos los archivos de la copia son restaurados.
-i Obtiene una lista de los archivos existentes en la copia. Ningún archivo es
restaurado.
-o Sobreescribe los archivos existentes. Si esta opción no se especifica, los archivos de
la copia que ya existan no son restaurados.
-t Indica que el dispositivo donde está la copia es una cinta.
-d Especifica el dispositivo donde se encuentra la copia de seguridad.
La orden tar:
La orden tar crea archivos de cinta (tarfile) y añade o extrae archivos. Un tarfile es
habitualmente una cinta magnética pero puede ser un archivo.
Letras de función:
u Los archivos especificados son añadidos al tarfile si éstos no están aún o si han sido
modificados desde la copia en este tarfile.
x Extrae los archivos nombrados desde el tarfile. Si no se especifican archivos, se
extraerán todos los archivos.
Opciones:
v Normalmente tar trabaja silenciosamente. Con esta opción, tar mostrará el nombre
de cada archivo.
f Usa el próximo argumento como nombre del tarfile.
La orden cpio:
cpio realiza copias de archivos a un archivo de copia de cpio. Los archivos de copia de cpio
contienen rutas de archivos e información de estado, junto con el contenido de los archivos
almacenados. Su sintaxis es la siguiente:
cpio -i | -o [opciones]
INTRODUCCIÓN:
donde:
Los campos 1 al 5 pueden tener una lista de valores separados por comas, un rango de
valores o un asterisco significando en esta caso que la tarea se ejecuta para todos los posibles valores
del campo. Si se especifica un día de la semana (en el campo día_semana) y en el campo día_mes se
pone un asterisco, se considerará sólo el día de la semana. Los resultados de la orden aparecerán en
la salida estándar si ésta no se redirecciona. Ejemplos:
0 0 * * * calendar
15 4 * * * /usr/etc/sa -s > /dev/null
0 0 * * 1-5 /usr/local/weekdays
40 0 * * 0,6 /usr/local/weekends
La orden calendar se ejecuta a medianoche cada día. sa se ejecuta a las 04:15 horas de cada
día. weekdays se ejecuta a medianoche de lunes a viernes de cada semana. weekends se ejecuta los
sábados y domingos de cada semana a las 00:40 horas.
Si la orden va a ser ejecutada una sola vez, se puede usar para ese caso la orden at
(explicada en el bloque 2).
LA ORDEN crontab :
Bloque 3: Administración del sistema. 85
El sistema dispone de una orden, llamada crontab, que permite crear, editar, borrar o listar
un archivo crontab de usuario. Su sintaxis es la siguiente:
crontab toma los comando que se van a ejecutar en el tiempo de la entrada estándar.
Opciones:
INTRODUCCIÓN:
Una de las responsabilidades del administrador del sistema es crear la mayoría de las noticias
(news) del sistema. Si hay otros usuarios en la máquina, es cortesía anunciar los tiempos de parada
planificados, la existencia de nuevo software y otra información actual. La orden news suele
utilizarse con este fin, puesto que los usuarios obtienen generalmente los anuncios de noticias cuando
se conectan a la máquina.
Otra característica que suele utilizarse para noticias de mayor prioridad es el motd (mensaje
del día), que se visualiza automáticamente para cada usuario cuando éstos se conectan.
Para anuncios de muy alta prioridad se puede utilizar la orden wall (mensaje para todos). La
orden wall lee un mensaje de su entrada estándar e inmediatamente lo escribe directamente al
terminal de todos los usuarios que están actualmente presentes en la máquina. Esta orden debería ser
utilizada para mensajes de valor inmediato, tal como una desconexión inminente del sistema.
LA ORDEN news:
La orden news permite a un usuario leer mensajes publicados por al administrador del
sistema. Se puede ejecutar news para visualizar todas las noticias creadas desde la última vez que se
ejecutó la orden, pero no las noticias antiguas que ya hayan sido examinadas. He aquí un ejemplo:
# news
Después se haber visto los mensajes una vez, no serán vueltos a visualizar si se ejecuta news
de nuevo. La orden news incluye algunas opciones para modificar su comportamiento implícito, estas
son:
-n Hace que news liste únicamente los nombres de las noticias que aún no han sido
examinadas.
-s Proporciona un recuento de las noticias aún por leer, sin listar sus nombres. Una de
estas dos opciones suele ser utilizada en el archivo de conexión (como el .profile o
el .cshsr) de modo que las noticias por leer se visualicen cada vez que se efectúe una
conexión ante la máquina.
-a Hace que news visualice todas las noticias disponibles, hayan sido o no leídas
previamente.
Cualesquiera otras opciones para la orden news se supone que son los nombres de los items
específicos que news va a visualizar, como en este ejemplo:
Bloque 3: Administración del sistema. 87
# news comida
# ls -l /usr/news
total 3
-rw-r--r-- 1 jim other 74 Jun 18 08:25 comida
-rw-r--r-- 1 pat other 125 Jun 18 08:26 junta
-rw-r--r-- 1 steve other 32 Jun 18 08:24 bienvenida
Otra facilidad con una función análoga es el mensaje del día. Aunque no existe una orden
específica, la mayoría de los sistemas incluyen la facilidad. El mensaje del día se utiliza generalmente
para dar a conocer mensajes de prioridad mayor que las noticias, tales como la hora prevista de
desconexión o los cambios de última hora en el sistema. En la práctica, el archivo de conexión
incluye la siguiente línea:
cat /etc/mot
Como el archivo de conexión se ejecuta cada vez que un usuario abre una sesión en la
máquina, el contenido del fichero motd se visualiza cada vez. A diferencia de news, este fichero se
visualiza cada vez que el usuario se conecta, de modo que los mensajes fuera de fecha contenidos en
este fichero tienden a ser tediosos muy rápidamente cuando los usuarios se presentan ante la máquina
repetidamente. El fichero /etc/motd debería de ser legible por todos pero mantenido (y, por tanto,
modificable) sólo por el superusuario.
LA ORDEN wall:
Bloque 3: Administración del sistema. 88
La orden write sólo permite comunicaciones con un sólo usuario designado como argumento
de la línea de orden. Ocasionalmente puede ser necesario enviar un mensaje a todos los usuarios
presentes en la máquina. Por ejemplo, las desconexiones del sistema deberían ser anunciadas para
advertir a todos los usuarios que aseguren sus sesiones antes de que el sistema sea desconectado10. En
vez de hacer un write a cada usuario individualmente, el sistema UNIX dispone de la orden wall.
Esta orden sólo es utilizable por administrador del sistema. Al igual que write, wall lee de la entrada
estándar el mensaje a enviar del modo siguiente:
Luego envía un mensaje a todos los usuarios que estén actualmente presentes, incluyendo a
su autor. No hay utilidad que permita a los receptores de wall contestar al remitente.
10
Esto lo realiza automáticamente el comando shutdown.
Bloque 3: Administración del sistema. 89
INTRODUCCIÓN:
DEFINICIÓN DE USUARIOS:
En un sistema UNIX, con un nivel de seguridad tradicional, existen tres archivos para la
creación y control de usuarios y dada su importancia se deben tener en cuenta las siguientes
recomendaciones:
/etc/passwd:
El administrador del sistema con clave de superusuario debe ser el único que debe tener los
permisos para modificar este archivo.
Tener una copia de respaldo en disquete e impresora para verificar que no ha sufrido
modificaciones o que sirva para procesos de recuperación.
Es importante estandarizar los nombres de los usuarios.
Definir grupos de usuarios con sus respectivos privilegios.
Identificar y remover o bloquear usuarios que no han sido usados o que no son necesarios;
estas cuentas que no son usadas pueden proveer fácilmente acceso a intrusos.
Guardar en un directorio especial con protección contra lectura, escritura y ejecución.
/etc/shadow:
El administrador del sistema con clave de superusuario debe ser el único que debe tener
permiso para modificar este archivo.
Tener una copia de respaldo en disquete e impresora para verificar que no ha sufrido
modificaciones o que sirva para procesos de recuperación.
Verificar que este archivo no tenga permisos de lectura para los usuarios.
Dar los parámetros para obligar al usuario a que cambie regularmente el password.
Detectar o identificar usuarios sin password y obligarlos a su definición.
Guardar en un directorio especial con protección contra lectura, escritura y ejecución.
/etc/group:
Bloque 3: Administración del sistema. 90
El superusuario debe ser el único que debe tener los permiso s para modificar este archivo.
Tener una copia de respaldo en disquete e impresora para verificar que no ha sufrido
modificaciones o que sirva para procesos de recuperación.
Estandarizar los nombres de los grupos con nombres claros.
Revisar los grupos que no tienen usuarios y depurarlos si es el caso.
Definir perfiles de usuarios para clasificar los usuarios en los grupos.
Identificar y reubicar los usuarios que tengan el mismo grupo de usuarios del sistema.
Tener una copia de seguridad de los archivos de usuario para evitar pérdidas por el mal uso
de los comandos.
Capacitar al personal usuario de UNIX sobre la importancia de generar periódicamente un
archivo con el comando l -i > archivo_respaldo, pues con él puede recuperarse
información valiosa, frente a un accidente o problemas del sistema.
Restringir el acceso a comandos como ps y kill.
Para usuarios especiales, en el archivo de arranque (.profile, .login, etc.) debe tener la
forma de que ubique al usuario en la aplicación que le corresponda, con el tipo de shell
asignado por el administrador.
Verificar que las variables de ambiente están bien definidas para cada usuario.
Enviar mensajes por terminal o por correo para recordar a los usuarios que se deben salir
correctamente del sistema antes de apagar la terminal.
Capacitar al administrador para que haga buen uso del comando ps.
Crear un shell script para generar reportes estadísticos producto del comando ps y realizar
los seguimientos a que haya lugar.
Chequear los procesos en background.
Identificar y comparar los archivos ocultos.
Comparar los archivos sensibles para identificar en que hora se produjo la última
modificación.
Limitarse el permiso de escritura a nivel de usuario, grupo y otros sobre los archivos de
arranque para evitar su alteración por parte de los mismos. Para propósitos de auditoría,
obtenerse copia impresa del contenido de estos archivos con alguna regularidad.
Listar por impresora los archivos anteriores para respaldar papeles de trabajo de la
auditoría y para facilitar la labor de análisis por parte del auditor de la información
contenida en tales archivos.
SEGURIDAD EN ARCHIVOS:
Definir qué usuarios pertenecen a un grupo y qué permisos deben tener sobre los archivos.
Revisar archivos importantes y verificar sus privilegios.
Crear directorios de trabajo con privilegios de lectura, escritura y ejecución solamente para
el propietario, para que ningún otro usuario tenga acceso.
Definir cuales deben ser los directorios protegidos contra borrado.
Restringir el cambio de grupo a los usuarios.
De los archivos básicos de las aplicaciones o del sistema, se debe establecer un
procedimiento para verificar los siguientes atributos:
Cambio en el nombre del archivo o directorio.
Mantener un log de los archivos para evaluar si los permisos se encuentran autorizados o si
las modificaciones temporales efectuados por el administrador del sistema se encuentran
todavía, es decir, nos permite verificar que los permisos dados a los archivos de los
diferentes usuarios correspondan al nivel de privilegios que estos posean.
Mantener un respaldo del árbol de organización de los archivos y sus respectivos permisos,
permitiendo así en caso de cualquier eventualidad una forma de mostrarnos cuál era el
estado de los permisos para los diferentes archivos y directorios del sistema es una etapa
precedente.
No es aconsejable ceder ciertos archivos a determinados usuarios, ya que estos pueden
cambiar los niveles de permisos y el usuario que cedió el archivo ya no tendría ninguna
facultad de manipulación del archivo.
El superusuario debe estar haciendo un permanente chequeo de los permisos otorgados a
los usuarios sobre los archivos, para estar controlando las modificaciones efectuadas y los
privilegios denominados públicos que un momento dado se le asigna a los archivos.
Recomendaciones generales:
sistema.
Buscar los archivos grandes de usuarios y solicitar a los usuarios depurar los
archivos grandes.
Generar una lista de errores y las acciones tomadas para futuras situaciones.
Mantener respaldo de los archivos que nos muestran los parámetros del kernel y la
distribución de los sistemas de archivos del disco (mtune, sysdef, divvy).
Establecer políticas claras sobre la distribución de los sistemas de archivos del disco.
Mantener un respaldo en disco duro y un dispositivo magnético del archivo de
configuración del sistema UNIX.
Los siguientes archivos se deben imprimir como papeles de trabajo y como soporte para una
futura instalación y soluciones de problemas.
group
passwd
hwconfig
swconfig
mtune
sysdef
divvy
hosts
inittab
messages
lpstat
Respaldo:
Boot.
RECOMENDACIONES ADICIONALES:
la mitad o final del password, estas claves deben ser fáciles de recordar por el
usuario.
Cada vez que se efectúen modificaciones al kernel es importante generar copia impresa y
magnética de los nuevos parámetros contenidos en el archivo mtune. Esto debería
implementarse mediante un shell script que generará un archivo de salida a través de la
ejecución del comando sysdef.
Restringir el acceso físico al computador.
Fijar los permisos de acceso a sus directorios y archivos, de tal manera que ellos puedan ser
accesados solamente por el propietario o en otro caso por el grupo u otros usuarios. No
dejar archivos públicos de escritura, sólo en algunos casos cuando exista una buena razón.
Asignar password a todos los usuarios y cambiarlos periódicamente.
Los usuarios deben chequear periódicamente la última vez que se accedió al sistema a
través de su login, para identificar si ha habido un uso desautorizado de su login, y cuanto
tiempo transcurrió.
Los usuarios, quienes pueden hacer uso del comando su, pueden ingresar con clave de root,
comprometiendo la seguridad de sus sistema, ya que pueden modificar archivos con el
desconocimiento de su propietario. Por esta razón es recomendable bloquear este comando,
o generar un log donde se guarde la utilización de este comando, se debe chequear el
archivo /var/adm/sulog donde se guarda la información permitida.
Colocar una apropiada máscara en el archivo de arranque para fijar un nivel de seguridad
para la creación de archivos y directorios.
No montar un medio (tal como un disquete, cinta, etc.) hasta que su contenido no se
verifique. Estos dispositivos pueden contener archivos con identificadores de usuarios
desconocidos, o pueden dañar información actualizada.
No adicionar paquetes o programas de origen desconocido.
Revisar todos los servicios de conexión de la red con el sistema.
Debe conservarse como papeles de trabajo por parte del auditor todos aquellos listados a
que hemos hecho referencia en los puntos anteriores.
Bloque 4: Redes en UNIX. 94
Una red es un medio de transmisión de datos que permite a los ordenadores compartir
recursos e información. Los medios de transmisión que se emplean en las redes de comunicaciones
son:
Estas dos técnicas se caracterizan por tener como medio de transmisión las diferentes capas
de la atmósfera. Existen distintas bandas de frecuencia por las que se pueden transmitir
señales de TV, radio, satélite, etc…
Fibra óptica:
A los computadores que forman parte de una red se les conoce como host o nodo. Una red
formada por computadores con la misma arquitectura se conoce como red homogénea. Si por el
contrario, los computadores tienen distintas arquitecturas, será una red heterogénea. Un protocolo de
red es un conjunto de reglas para la comunicación en una red entre dos hosts. Un protocolo puede
definir cómo se identifican los hosts en una red; la forma que tomarán los datos en la transmisión; o
bien, cómo esta información se debe procesar en el destino final
Las redes se pueden clasificar según su alcance en:
Bloque 4: Redes en UNIX. 95
También se pueden distinguir las redes según el tipo de conmutación usada. Existen tres
tipos:
Redes con conmutación de circuitos: Si dos ordenadores quieren comunicarse entre sí,
deben establecer previamente una línea permanente o dedicada (canal físico), durante el
tiempo de la transmisión de información, por la que circularán los mensajes (como cuando
queremos hablar por teléfono). La información no se comprueba y por tanto, no hay
retardos de tiempo.
Redes con conmutación de paquetes: La información se fragmenta en unidades de
información llamadas paquetes que son enviados a través de la red. En la red existe un
control de flujo y de errores. La red proporciona a cada paquete para su transmisión un
enlace físico. Dependiendo de que el enlace se mantenga o no durante la comunicación,
para los paquetes que componen la información, hablaremos de técnica datagrama o
circuito virtual:
Datagrama: Los paquetes se pueden transmitir por distintos canales físicos.
están asignados al mismo enlace físico, o sea, se establece para cada comunicación
un canal lógico.
Redes con conmutación de mensajes: La información se fracciona en unidades de
información, llamadas mensajes, de longitud variable. La red, al igual que en la
conmutación de paquetes, provee un canal. Los mensajes se transfieren de forma completa
de nodo a nodo, donde se comprueban y se corrigen los errores. Los mensajes en un
determinado nodo no se destruyen hasta que no se haya comprobado que han sido recibidos
correctamente en el posterior.
Una red de UNIX es un grupo de al menos dos estaciones de trabajo conectados por algún
mecanismo como puede ser un cable. Hay varios tipos de estaciones de trabajo:
Servidor: Es una estación con disco que suministra servicios (como correo, acceso a
sistemas de archivos, acceso a bases de datos, …) a otras máquinas en una red.
Cliente: Es una estación que solicita recursos de red a un servidor, como puede ser correo,
almacenamiento en disco, etc.
Standalone: Una estación con sus propios recursos, como puede ser su propio disco,
sistema de archivos, correo, bases de datos, etc. Se pueden conectar a una red. En algunos
casos, una estación standalone puede actuar como un servidor para otras máquinas cliente.
Redes de área local (LANs): Es un sistema de comunicaciones que permite que un número
de dispositivos independientes se comuniquen directamente unos con otros, dentro de un
área geográfica de tamaño moderado y sobre un canal físico de comunicaciones de
velocidad también moderada. La forma de conectarse suele ser mediante cable. Dos tipos de
redes LAN comunes a UNIX se basan en las tecnologías Ethernet y FDDI. Tales redes
Bloque 4: Redes en UNIX. 96
permiten la comunicación entre máquinas en tiempo real; con lo cual, se pueden realizar
operaciones como acceder a un archivo que esté almacenado en el disco de otro ordenador,
usar el disco de otro ordenador para almacenar sus propios archivos, imprimir trabajos
tanto en una impresora local como en la de otro ordenador, enviar mensajes entre los
usuarios o grupos de usuarios que forman parte de la red, trabajar con aplicaciones
distribuidas basadas en el modelo cliente/servidor, etc.
Redes basadas en ARPANET: En 1969 ARPA (Advanced Research Projects Agency) del
Departamento de Defensa de los EE.UU. patrocinó el desarrollo de un protocolo de
comunicación y red de banda ancha. Su descendiente se llama Internet, el cual está
compuesto de un número de redes interconectadas que usan el protocolo Internet (IP). Los
usuarios en máquinas que usan Internet, por cable u ondas; pueden conectarse en tiempo
real a otras máquinas de la red.
Redes UUCP: La red UUCP (Unix to Unix Copy Program) no es un sistema hardware
permanente que conecta máquinas, pero permite a las máquinas usar teléfonos para
transmitir datos. No es una red en tiempo real; por tanto, no podemos conectarnos a otra
máquina con UUCP. Se puede enviar información a otra máquinas y recibir respuestas de
ellas. Se puede usar redes UUCP para enviar correo sobre redes basadas en ARPANET.
INTRODUCCIÓN A TCP/IP:
TCP/IP fue desarrollado originalmente por el Dpto. de Defensa de los EE.UU. El término
Internet describe a la familia de protocolos junto con la red; sin embargo se usa el término TCP/IP
(por los dos protocolos más utilizados a nivel de transporte y físico) para referenciar a la colección de
protocolos Internet. TCP/IP proporciona servicios para muchos tipos diferentes de hosts conectados a
redes heterogéneas. Estas redes pueden ser redes de área ancha, como las basadas en X.25, o bien
redes locales. TCP/IP se diseñó cumpliendo los siguientes requerimientos:
Cada máquina UNIX inicia TCP/IP a través de los scripts /etc/rc.boot y /etc/rc.local. Para la
gestión de Internet existe un proceso del sistema de servicios Internet, inetd, que se ejecuta
normalmente en tiempo de arranque a través del script /etc/rc.local. Este proceso escucha las posibles
conexiones en las direcciones Internet de los servicios que especifique su archivo de configuración.
Cuando se detecta una conexión, llama al proceso servidor especificado para el servicio solicitado y,
dependiendo del servicio, inetd seguirá escuchando en el buzón o esperará hasta que el servidor haya
finalizado. Esto se hace para evitar un exceso de procesos ejecutándose a la vez.
Las redes pueden ampliarse enlazando redes de área local a través de un computador llamado
IP router. Se conoce como un internetwork a una configuración de red consistente de varias redes
enlazadas por routers. Cuando queramos ampliar la red local o queramos crear un internetwork es
posible que se necesite el siguiente hardware:
Bloque 4: Redes en UNIX. 97
Repetidor: Es un dispositivo usado a nivel físico de la red para conectar dos segmentos de
red. Permite por tanto extender la longitud máxima de la red. Se encarga de copiar cada bit
del paquete de un segmento o subred a otro; o dicho de otra forma, es un regenerador de
señal a nivel físico.
Puente: Es un dispositivo usado a nivel de enlace de datos de la arquitectura de red. Copia
paquetes selectivamente desde una red a otra del mismo tipo (con el mismo MAC pero
puede tener diferente medio de transmisión). Extiende la longitud máxima de la red (incluye
las funciones de un repetidor).
Enrutador: Trabaja a nivel de red. Es un dispositivo que envía paquetes desde una red
lógica a otra; o sea, realiza operaciones de internetworking. Por tanto, puede conectar
LANs con diferentes MAC (por ejemplo, IEEE 802.3 con Token Ring) e incluso con
diferentes topologías. Una red lógica trabaja sólo con un protocolo particular. Normalmente
existe una red lógica por cada red física.
Gateway: Este dispositivo y su software asociado, permite que se puedan comunicar redes
que usen diferentes protocolos; o sea, realiza conversiones de protocolos. Pueden llegar a
diferir en todos los niveles de la arquitectura de red.
El modelo OSI:
11
Existen otras arquitecturas de red que pueden ser de interés su estudio aunque el que se utiliza como
referencia es normalmente la arquitectura OSI. Algunas de estas arquitecturas son la SNA, diseñada por
IBM, la DNA de Digital y la DSA de Bull.
Bloque 4: Redes en UNIX. 98
Nivel físico:
Es el encargado de la transmisión de series de bits por un canal de comunicación.
Nivel de enlace:
Recoge los bits proporcionados por el nivel 1 y los transforma en un conjunto que aparece
libres de errores de transmisión para pasarlos al nivel de red. Esto se consigue realizando la
partición de los datos de entrada en unidades de información llamadas tramas de datos. En
el nivel de enlace de las redes de área local se añaden normalmente dos responsabilidades,
no consideradas en redes de área amplia, el control de acceso al medio (debido a que
pueden existir varias comunicaciones simultáneas) y la capacidad de direccionamiento
(para asignar las direcciones que especifican quiénes son los ordenadores fuentes y destino).
Todo esto hace que el nivel de enlace se divida en dos subniveles: el subnivel de control de
acceso al medio (MAC), situado por encima del nivel físico; y el subnivel de enlace lógico
propiamente dicho (LLC), situado encima de MAC.
Nivel de red:
Controla las operaciones de la red. Entre otras cosas, define las principales características del
interfaz Host/Sistemas de tránsito, y cómo los paquetes, unidades de información a este
nivel, son encaminados dentro de la red.
Nivel de transporte:
Se conoce también como nivel Host/Host. La función básica del nivel de transporte consiste
en aceptar los datos del nivel de sesión, partirlos en unidades más pequeñas si fuera
necesario, pasarlos al nivel de red y asegurar que todas esas unidades de información
lleguen correctamente al otro extremo. La conexión más corriente a este nivel de transporte
es en circuito virtual que entrega los mensajes en el orden en que fueron recibidos.
Nivel de sesión:
Es a través de este nivel con el que el usuario debe establecer la conexión con un proceso en
otro sistema. Para establecer una sesión, el usuario debe proporcionar la dirección remota
con la que se quiere conectar. En este nivel se convertirá la dirección de sesión en la
dirección de transporte.
Nivel de presentación:
Este nivel realiza varia funciones que se requieren para solucionar problemas de los usuarios.
Algunas de estas funciones van orientadas a transformaciones criptográficas, compresión
de texto, compatibilidad de terminales y transferencia de archivos.
Nivel de aplicación:
Corresponde a este nivel las utilidades o servicios que se ofrecen a los usuarios.
Normalmente se busca conseguir la transparencia de red, ocultación de recursos, etc…
Bloque 4: Redes en UNIX. 99
APLICACIÓN
APLICACIÓN
PRESENTACIÓN
SESIÓN
TRANSPORTE
TRANSPORTE
RED RED
ENLACE ENLACE
FISICO FISICO
Servicios de TCP/IP:
Los servicios principales que se tienen en los distintos niveles de TCP/IP son los siguientes:
RED IP
ETHERNET ARP
ENLACE RARP
ETHERNET TOKEN RING
FISICO IEEE 802.5 FFDI
Nivel físico:
Es el nivel de hardware. Los protocolos a nivel físico transmiten datos en forma de paquetes.
En este nivel, TCP/IP soporta varios protocolos entre los que se incluye Ethernet, IEEE
802.5, FDDI, Token Ring, etc.
Nivel de enlace:
El controlador Ethernet es un ejemplo de estándar soportado por este nivel. Existen dos
protocolos, ARP y RARP, que se sitúan entre el nivel de red y el nivel de enlace. ARP es el
protocolo de resolución de direcciones Ethernet (Ethernet Address Resolution Protocol). Se
encarga de asignar direcciones IP (32 bits) a direcciones Ethernet (48 bits). Esta dirección
se convierte porque para poder mandar la información necesitamos la dirección física.
RARP o Reverse ARP es el protocolo de resolución de direcciones IP. Asigna direcciones
Ethernet a direcciones IP. Se utiliza en estaciones sin disco. ARP y RARP no se usan si no
se utiliza Ethernet
Nivel de red:
independientemente de las otras (un ordenador puede estar desconectado, puede tener una
ruta mal configurada, etc...). El protocolo ICMP permite que un host o gateway mande
informes de errores o mensajes de control a otros gateways o hosts. Los mensajes de ICMP
lo usa el software de Internet y no los procesos de usuario. Algunos errores son por fallos
de enrutamiento, vencimiento de tiempo de vida del datagrama, información de rutas
mejores, excesivas pérdidas de paquetes, etc.
Nivel de transporte:
En este nivel existe una gran variedad de protocolos TCP/IP. Básicamente todos estos
servicios se pueden descomponer en cuatro grandes grupos:
Servicios de conexión remota; como telnet, rlogin y remsh.
DIRECCIONES INTERNET:
Para que los hosts puedan comunicarse entre sí es necesaria la siguiente información:
Cada host en una red TCP/IP está identificado, generalmente, por una única dirección
Internet. Esta dirección es independiente de la dirección física.
Cada dirección Internet, también conocida como dirección IP, está formada por 32 bits. La
dirección se divide en dos partes: una corresponde a la red y otra al host. El organismo encargado de
gestionar las direcciones, NIC (Network Information Center), ha establecido cinco clases de
direcciones; aunque sólo tres de ellas son las básicas (A, B, C).
Bloque 4: Redes en UNIX. 101
Dicho de otra forma, dividiendo la dirección Internet en bytes, los valores posibles del primer
byte para la clase A estarán comprendidos entre 1-126, para la clase B entre 128-191 y para la clase
C entre 192-223. Los tres primeros bits de una dirección determinan su clase. Estas máscaras de bits
lo usan los enrutadores para determinar que bits de una dirección Internet pertenecen a la dirección de
red.
Los ordenadores que están conectados a más de una red tendrán tantas direcciones IP como
número de conexiones de red tengan. Además, existen direcciones especiales:
Además hay esquemas de direccionamiento para multicasting (valor 224), es decir, mensajes
dirigidos a un grupo de ordenadores.
La ventaja de esta forma de direccionamiento es que es un esquema muy eficiente; el
ordenador tiene que hacer pocos cálculos para saber qué es lo que ha de hacer con el paquete. Los
inconvenientes son: si se cambia el ordenador de un sitio a otro, hay que cambiar la dirección IP,
cambiar un conjunto de redes de una clase a otra implica realizar muchos cambios y el enrutamiento
no es claro ya que pueden existir ordenadores con más de una dirección IP.
Normalmente las direcciones IP serán de tipo decimal, donde cada byte es separado por un
punto decimal; por ejemplo, 128.10.2.30. En la actualidad se usan nombres en lugar de números y
luego se traducen a direcciones IP.
Dentro de una red, los hosts pueden estar agrupados en redes físicas más pequeñas llamados
subredes. Para ello se utiliza la máscara de subred (subnet mask). Esto nos permite cambiar redes de
clase A a redes de clase B o C o bien, redes de clase B a redes de clase C. Por ejemplo, si una
empresa tiene dos redes físicas Ethernet compartiendo una dirección de clase A, 91.0.0.0, los hosts de
una de las redes tendrán las direcciones 91.1.X.X y los otros hosts, de la otra red, las direcciones
91.2.X.X. Este particionamiento de la red no es visible para los hosts que no estén en la red
subdividida (sólo ven una única red).
ENRUTAMIENTO:
Cuando el host destino no está en la misma red, el host emisor debe identificar un gateway al
cual enviar los datos. El gateway enviará a su vez los datos hacia la red destino. En este caso, se
estará utilizando una ruta indirecta. Este enrutamiento se realiza mediante tablas. En cada máquina
se guarda una tabla de parejas de direcciones (red_destino, gateway) donde la dirección indicada por
red_destino identificará a la red destino a la cual va dirigida la información y la otra dirección,
indicada por gateway, indica el siguiente gateway al cual se hace la entrega. Si no se requiere otro
gateway intermedio, se pondrá una marca especial para indicar la entrega directa.
Nótese que un gateway sólo conoce la dirección del gateway siguiente y no el enrutamiento
completo, y que la siguiente estación del datagrama se encuentra en la misma red a la que pertenece
el gateway. Mirando la figura 1.5, las direcciones inferiores se corresponden con la comunicación a la
derecha y las superiores, con la izquierda.
El enrutamiento puede realizarse a hosts específicos o a redes específicas. Para ello de utiliza
la orden route. Si se quiere guardar la información del enrutamiento se debe actualizar el archivo
/etc/gateways.eth para cada ruta que se quiera añadir.
Bloque 5: Programación con la interfaz del sistema. 103
TEMA 1. EL COMPILADOR DE C.
1. Con un editor, escribir y guardar el código fuente del programa en C. Utilizar un nombre
con extensión .c (Por ejemplo prueba.c).
2. Para compilarlo se utiliza el comando cc. Si no hay errores, el resultado de la compilación
se guardará en un archivo que por defecto se llama a.out.
3. Para ejecutarlo basta con escribir el nombre del archivo:
% a.out
EL COMPILADOR cc:
Sintaxis:
INTRODUCCIÓN:
- dbx
- dbxtool
- adb
dbx:
dbxtool:
Depurador basado en una interface de ventanas para dbx. Similar a dbx salvo que es más
cómodo de manejar porque permite usar el ratón. Incluye una ventana para ejecutar cualquiera de los
comandos existentes en dbx.
adb:
dbx y dbxtool son mucho más fáciles de utilizar que adb y además, contienen todos los
aspectos necesarios para la depuración. adb es más útil para la observación interactiva de archivos
binarios sin símbolos ni código objeto. Se utiliza para depurar código objeto cuando no disponemos
del fuente y para depurar el kernel.
- Post-mortem.
- Proceso vivo.
Bloque 5: Programación con la interfaz del sistema. 106
- Multiproceso.
Post-mortem:
Proceso vivo:
Multiproceso:
La depuración multiproceso es útil cuando depuramos dos procesos que están estrechamente
ligados. Por ejemplo en una red puede haber un programa cliente y otro servidor (que intercambian
información, llamadas a procedimientos, etc.). Para depurar ambos es necesario que cada uno haya
iniciado la depuración con dbx. No se permiten depuraciones remotas sino que éstas deben hacerse
sobre la misma máquina.
dbx:
Para que un archivo sea depurable, el proceso de compilación debe realizarse incluyendo el
argumento -g en la línea de llamada al compilador cc. Este parámetro indica al compilador que
incluya cierta información en el archivo objeto, que será imprescindible para la depuración.
El prompt (dbx) nos indica que espera algún comando dbx. Para salir del depurador basta
con indicar:
(dbx) quit
Operaciones en dbx:
Ejecución de programas:
(dbx) rerun
Igual que el anterior salvo que utiliza los argumentos de la última ejecución.
(dbx) cd [dir]
(dbx) pwd
(dbx) sh comando
Ejecuta un comando del shell.
PRÁCTICA:
Para practicar con el compilador de C (cc) y el depurador (dbx), construya un programa que
lea un archivo de texto que se le pase como parámetro y que cuente el número de caracteres, de
palabras y de líneas del mismo.
Bloque 5: Programación con la interfaz del sistema. 111
INTRODUCCIÓN:
La única forma que existe en el sistema operativo UNIX para acceder a los servicios del
kernel es mediante las llamadas al sistema. Algunos de los servicios que se pueden obtener son los
correspondientes a los sistemas de archivos, a los mecanismos d multitarea y a las primitivas de
comunicación entre procesos.
En definitiva, las llamadas al sistema definen la interfaz entre el kernel y los programas de
usuario que se ejecutan en el nivel superior; o dicho de otra forma, definen lo que es UNIX.
Otros servicios de más alto nivel que podemos utilizar en el entorno de programación son
aquellas que nos ofrece las rutinas de las librerías del compilador.
Veamos algunos conceptos básicos que pueden ser necesarios cuando se programe en UNIX:
Descriptor: Es un entero asignado por el sistema que nos permite referenciar unívocamente
a un archivo, buzón (socket), grupo de semáforos, etc. para poder realizar operaciones con
éstos.
Grupo de procesos tty (Tty Process Group): Cada proceso activo puede ser miembro de un
grupo de terminal que se identifica por un entero positivo llamado ID de grupo de procesos
tty. Esta agrupación se usa para arbitrar entre múltiples trabajos que se encuentren en el
mismo terminal y para dirigir señales al grupo de procesos apropiado.
ID de usuario efectivo, ID de grupo efectivo y Grupos de acceso: El acceso a los recursos
del sistema se controla mediante tres valores, el ID de usuario efectivo, el ID de grupo
efectivo y los IDs de grupo suplementarios. El ID de usuario efectivo e ID de grupo
efectivo son normalmente el ID de usuario real e ID de grupo real del proceso
respectivamente. Pero ambos pueden ser modificados mediante el bit setuid o el bit setgid
del proceso ejecutado.
ID del proceso padre (Parent Process ID): Un nuevo proceso se crea a partir de un proceso
fork activo. El ID del proceso padre de un proceso es el ID de proceso de su creador.
ID de grupo de procesos (Process Group ID): Cada proceso activo es miembro de un grupo
de procesos que se identifica por un entero positivo llamado ID de grupo de procesos. Esta
agrupación permite la señalización de procesos relacionados y los mecanismos de control
de trabajos.
ID de usuario real e ID de grupo real: Cada usuario en el sistema se identifica por un entero
positivo conocido como el ID de usuario real. Cada usuario pertenece al menos a un grupo,
conocido como ID de grupo real.
Procesos especiales (Special processes): Los procesos con ID de proceso 0, 1 y 2 son
especiales. El proceso 0 es el scheduler. El proceso 1 es el proceso de inicialización init, y
por tanto el ascendiente de cualquier otro proceso del sistema. Se usa para el control de la
estructura de procesos. El proceso 2 es el proceso de swapping.
Señal (Signal): Las señales se usan para notificar sucesos asíncronos. Las señales se
pueden dirigir a procesos, grupos de procesos y a otras combinaciones de procesos. Las
señales las pueden enviar un proceso o el propio sistema operativo.
Sesión (Session): Cada proceso es miembro de una sesión. Con cada terminal de control se
asocia una sesión en el sistema, como ocurre con los shells de conexión.
Terminal de control (Controlling Terminal): Un terminal que se asocia con una sesión. Cada
sesión puede tener al menos un terminal de control. Un terminal puede ser el terminal de
Bloque 5: Programación con la interfaz del sistema. 112
control de al menos una sesión. El terminal de control se usa para dirigir señales (como
interrupciones o señales de control de trabajos) a los procesos apropiados.
Estudiemos como ejemplo las llamadas al sistema que se emplean en la creación y ejecución
de procesos, en el manejo de semáforos, en la compartición de memoria y en la estructura básica de
un programa cliente/servidor.
Bloque 5: Programación con la interfaz del sistema. 113
CONCEPTOS BÁSICOS:
CREACIÓN DE PROCESOS:
La única forma que existe para que un usuario pueda crear un nuevo proceso en UNIX es
ejecutando la llamada al sistema fork. Esta llamada hace que el proceso que la ejecute se divida en
dos procesos. Al proceso que ejecuta fork se le conoce como proceso padre y al nuevo proceso creado
se le llama proceso hijo. La sintaxis de fork es:
Tras ejecutarse esta llamada al sistema, los dos procesos tendrán copias idénticas de su
contexto a nivel de usuario. La única diferencia será que el valor entero que devuelve fork
(correspondiente al PID) para el proceso padre el ID del proceso hijo mientras que para el proceso
hijo es 0. Estos valores se utilizan para determinar el código que ejecutará cada proceso (ver ejemplo
más adelante). En caso de error, devuelve el valor -1. Además, ambos procesos compartirán los
archivos que el proceso padre tenía abiertos hasta el momento de la llamada al sistema. Y por último,
el proceso hijo recién creado heredará los IDs de usuario (real y efectivo) del proceso padre, el grupo
de proceso padre, el directorio actual y el valor “nice” del padre; el cual de usa para calcular la
prioridad de planificación.
Bloque 5: Programación con la interfaz del sistema. 114
Todos los procesos en el sistema, excepto el proceso 0, se crea mediante esta llamada al
sistema12.
El kernel asocia dos IDs de usuario con cada proceso (heredados por el proceso padre, como
se ha dicho anteriormente), independiente del ID del proceso; el ID de usuario real (RUID) y el ID de
usuario efectivo (EUID) o setuid (Set User ID). El ID de usuario real identifica al usuario
responsable del proceso que se va a ejecutar mientras que el usuario efectivo se obtiene cuando se
hereda el bit setuid del modo de permisos de un archivo y consiste en que un usuario (sólo durante la
ejecución del programa) tendrá los privilegios del propietario de un archivo ejecutable, como si el
usuario que está ejecutando el programa fuera el propietario del archivo. Con esto conseguiremos
acceder a archivos de datos que pueda manejar el programa y para los cuales no se tenía permiso. Un
ejemplo se tiene con la orden passwd, el cual accede a un archivo de datos (/etc/passwd) que no
podría ser modificado directamente por un usuario normal.
El sistema impone (aunque es configurable) un límite en el número de procesos que un
usuario puede ejecutar simultáneamente. De esta forma evitamos que se sature la tabla de procesos
ya que podría impedir que otros usuarios pudieran crear procesos. Estas limitaciones no afectan al
superusuario.
Considere el siguiente ejemplo. Consiste en un método para compartir el acceso a archivos
mediante la llamada al sistema fork. Así, ambos procesos (padre e hijo) leerán la información del
archivo existente y luego lo escribirán en un archivo nuevo. Para ejecutarlo, un usuario deberá
escribir el nombre del programa con dos parámetros: (1) el nombre de un archivo existente y (2) el
nombre del nuevo archivo a crear. Cada proceso podrá acceder a su copia privada de las variables
pero ninguno podrá acceder a las variables del otro proceso.
/* hijpad.c */
#include <fcntl.h>
int fdrd,fdwt;
char c;
main (argc,argv)
int argc;
char *argv[];
{
int status;
if (argc!=3)
{
printf ("\nFaltan parametros.\n");
exit (1);
}
if ((fdrd=open(argv[1],O_RDONLY))==-1)
{
printf ("\nNo se puede leer el archivo de entrada.\n");
exit(1);
}
if ((fdwt=creat(argv[2],0666))==-1)
{
printf ("\nNo se puede crear el archivo de salida.\n");
exit(1);
}
12
En algunas versiones modernas de UNIX, desaparece el proceso 0 y así, todos los procesos descienden del
proceso init (proceso 1).
Bloque 5: Programación con la interfaz del sistema. 115
printf ("Status=%d",status);
switch (fork()) {
case -1: /* Gestión del error */
exit (1);
break;
case 0: /* Proceso hijo */
rdwrt();
exit (0);
break;
default: /* Proceso padre */
rdwrt();
wait (&status); /* espera a que termine el proceso hijo */
break;
} /* fin del switch */
} /* fin de main */
rdwrt ()
{
for (;;) {
if (read(fdrd, &c,1)==0=
return;
write (fdwt, &c, 1);
}
} /* fin de rdwrt */
Note que ambos procesos ejecutan el mismo código para poder así compartir el acceso al
archivo.
EJECUCIÓN DE PROCESOS:
donde filename es el nombre del archivo a ejecutar, argv es un puntero a una lista de cadenas que
corresponderán con los parámetros del programa ejecutable y envp es un puntero a una lista de
punteros a cadenas que corresponden con el entorno del programa a ejecutar. Las cadenas se
caracteres en el entorno son de la forma “nombre=valor” y pueden contener información útil para los
programas como pueden ser el directorio de trabajo del usuario, caminos de directorios para buscar
programas ejecutables, etc. Los procesos pueden también acceder a su entorno a través de la variable
global environ (su declaración es de la forma siguiente: extern char **environ) inicializada por las
rutinas del C.
Hay varias funciones de las librerías del lenguaje C que permiten también ejecutar programas
como son execl, execc, execlp y execvp. Se diferencian en el tipo de información que se pasa como
parámetros. Estas funciones, junto con la llamada al sistema execve, forman la familia exec. Muchas
de estas funciones son más sencillas de usar que la llamada la sistema; como podemos apreciar en el
próximo ejemplo.
Bloque 5: Programación con la interfaz del sistema. 116
En el ejemplo siguiente, el programa crea un proceso hijo que ejecuta la función execl:
/* crear.c */
main()
{
int status;
if (fork()==0)
execl ("/bin/date","date",0);
wait (&status);
}
wait (estado);
int *estado;
Tras su ejecución, devuelve el PID del proceso hijo en cuestión y coloca en estado el estado
de salida proporcionado por éste. Devuelve -1 si no existe ningún proceso hijo del proceso que envía
la llamada. Podemos decir que wait() se utiliza para la sincronización de los dos procesos (padre e
hijo) que se están ejecutando concurrentemente.
La llamada al sistema exit() provoca la finalización de un proceso. Los 8 bits menos
significativos del argumento quedan a disposición del proceso padre.
Un proceso puede finalizar bien cuando se ejecuta exit o bien cuando termina la ejecución de
su código.
PRÁCTICA:
Construya un pequeño shell ayudándose de las llamadas al sistema que se acaban de ver. El
programa debe mostrar un prompt y ejecutará los comandos que se le especifiquen. El shell terminará
su ejecución cuando se le introduzca una cadena determinada.
Bloque 5: Programación con la interfaz del sistema. 117
TEMA 5. SEMÁFOROS.
CONCEPTOS BÁSICOS:
La llamada al sistema semget crea una lista de semáforos (también se habla de conjunto de
semáforos) o devuelve un identificador (ID) a una lista si ésta ya existía. Su sintaxis es la siguiente:
13
En alguna bibliografía, a estas operaciones se les conoce como wait y signal, pero en el entorno UNIX
existen dos llamadas al sistema con estos mismos nombres y no tienen el mismo significado; por lo que
utilizaremos P y V.
Bloque 5: Programación con la interfaz del sistema. 118
Tabla de
semáforos Listas de semáforos
0 1 2 3 4 5 6
0 1 2
0
0 1 2
.
.
.
.
.
.
Si el bit IPC_CREAT del parámetro semflg está activo, el conjunto se creará a no ser que
éste existiera ya. Otros banderines que se pueden establecer son los permisos de la región (al igual
que los archivos). Habrá nsem semáforos en el conjunto, numerados a partir de 0. El valor que
devuelve (lo llamaremos semid) es de tipo entero y corresponde al identificador del conjunto de
semáforos; en caso de error, devuelve -1.
Los procesos manipulan los semáforos con la llamada semop. Su sintaxis es la siguiente:
struct sembuf {
unsigned short sem_num; /* número de semáforo dentro de la lista */
short sem_op; /* operación de semáforos */
short sem_flg; /* banderines de operación */
};
nsemop es el tamaño de la lista. El valor de tipo entero que devuelve la función es el valor del
último semáforo operado en el conjunto antes de hacer la operación.
El kernel lee la lista de operaciones de semáforos, semops, desde el espacio de
direccionamiento del usuario y verifica que los números de semáforos son legales y que el proceso
tiene los permisos necesarios para leer o cambiar los semáforos. En caso contrario, la llamada al
sistema fallará.
Podría ocurrir situaciones peligrosas si un proceso realiza una operación sobre un semáforo,
presumiblemente apoderándose o cerrando (locking) algún recurso, y después salir (exit) sin
restablecer el valor del semáforo. Estas situaciones pueden ser debidas como consecuencia del
resultado de un error del programador u otra circunstancia que cause la terminación de un proceso.
Para evitar tales problemas, un proceso puede establecer el banderín SEM_UNDO en la llamada al
Bloque 5: Programación con la interfaz del sistema. 119
sistema semop; así, cuando éste sale, el kernel invierte14 (reverse) el efecto de cada operación sobre el
semáforo que el proceso haya hecho. El efecto neto es dejar el semáforo con el valor con que se
inició.
La llamada al sistema semctl permite realizar operaciones de control sobre los semáforos. Su
sintaxis es:
Las operaciones a realizar se especifican con cmd y afectan bien a un semáforo o bien a
todos los semáforos que forman parte del conjunto de semáforos especificados con semid. En caso de
que el comando vaya dirigido a un semáforo, éste estará identificado con semnum; y si va dirigido a
todos, semnum especificará el número de semáforos sobre el que se va a actuar. arg se declara como
una unión de la forma siguiente:
union semun {
int val;
struct semid_ds *semstat;
unsighned short *array;
};
/* semaforo.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define SEMKEY 76
main ()
{
/* Declaracion de variables */
int semid; /* ID de la lista de semaforos */
14
La forma de conseguir esta inversión es complicada de ver y se impone la claridad del estudio frente a la
complejidad que supondría su explicación ya que no es imprescindible su conocimiento.
Bloque 5: Programación con la interfaz del sistema. 120
} /* Fin de main */
PRÁCTICA:
CONCEPTOS BÁSICOS:
shmget Crea una nueva región de memoria compartida o devuelve una existente.
shmat Une lógicamente una región al espacio de direccionamiento virtual de un
proceso.
shmdt Separa una región del espacio de direccionamiento virtual de un proceso.
shmctl Manipula varios parámetros asociados con la memoria compartida.
Los procesos leen y escriben en la memoria compartida usando las mismas instrucciones que
cuando utilizan la memoria ordinaria; una vez que dicha memoria compartida ha sido incluida como
parte del espacio de direccionamiento del proceso.
Para la gestión de la memoria compartida, el kernel manipula tres tablas:
Tabla de Tabla de Tabla del
memoria regiones proceso
compartida
(después de
. shmat)
. .
. . .
. . .
. . .
. . .
.
.
.
.
.
.
Figura 6.1: Tablas usadas por el kernel para gestionar la memoria compartida.
Bloque 5: Programación con la interfaz del sistema. 122
La tabla de memoria compartida (shared memory table) contiene una entrada por cada región
distinta que se está compartiendo en el sistema; la tabla de regiones (region table) contiene una
entrada por cada región y por último, la tabla del proceso o tabla de regiones por proceso (process
table - per process region table) contiene las entradas correspondientes a las regiones que forman el
espacio de direccionamiento del proceso. Existirá una tabla del proceso por cada proceso del sistema.
La sintaxis de shmget es la siguiente:
donde size es el número de bytes de la región. El kernel busca en la tabla de memoria compartida por
la clave (key) dada. La clave será un valor entero único para todos los procesos que comparten la
misma región de memoria. Si existe una entrada, y los permisos lo permiten, devuelve un
identificador a la región (en adelante shmid). Si no lo encuentra y el usuario había establecido el
banderín (flag) IPC_CREAT, el kernel creará una nueva región. Otros banderines que se pueden
establecer son los permisos a la región.
En caso de que se produzca un error, se devuelve -1. La región de memoria quedará
reservada y sólo se asignará al espacio de direcciones de los procesos (tablas de páginas) cuando
éstos se unan a la región, mediante la correspondiente llamada a shmat. La sintaxis de esta llamada al
sistema es la siguiente:
donde shmid, devuelto por la función shmget, identifica a la región de memoria compartida; addr es
la dirección virtual donde el usuario quiere unir la memoria compartida; y flag especifica si la región
es de sólo lectura y si el kernel debería completar la dirección especificada por el usuario. El valor
que devuelve (virtaddr) es la dirección virtual donde el kernel a unido la región, no necesariamente el
valor solicitado por el proceso. En caso de error, se devuelve -1.
Cuando se ejecuta shmat, el kernel verifica que el proceso tiene los permisos necesarios para
acceder a la región. Si la dirección especificada por el proceso es 0, el kernel elige una dirección
virtual conveniente.
Es necesario tener en cuenta que los procesos pueden incrementar el tamaño de su región de
datos y pila. Cuando se hace, se asignan regiones nuevas contiguas virtualmente con las existentes;
por ello, no se debe de utilizar shmat con direcciones que pudieran impedir esto.
Un proceso separa una región de memoria compartida desde su espacio de direcciones
virtuales mediante:
donde addr es la dirección virtual devuelta por shmat. Aunque parezca más lógico pasar a esta
llamada un identificador, se usa una dirección para poder identificar entre varias instancias de la
región de memoria compartida que estén unidas a sus espacios de direcciones.
Un proceso usa la llamada al sistema shmctl para buscar el estado y establecer parámetros
de la región de memoria compartida. Su sintaxis es:
IPC_STAT Sitúa el valor actual de cada elemento de la estructura de datos asociada con
shmid en la estructura apuntada por shmststbuf.
IPC_SET Establece el valor de los siguientes elementos de la estructura de datos
asociada con shmid, obtenidos a partir de la estructura de datos apuntada
por shmstatbuf.
IPC_RMID Elimina del sistema el ID de memoria compartida especificada con shmid.
/* memoria.c
Descripcion: Sincronizacion entre dos o mas procesos; es decir,
este proceso no avanza hasta que otro proceso no
ponga un valor distinto de cero en una posicion de
memoria compartida
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHMKEY 70
#define SEMKEY 60
#define PRINC 0
int semid,shmid;
char *addr;
int *pint;
struct sembuf sem_oper;
union semun arg;
struct shmid_ds *shmstatbuf;
main ()
{
semid = semget (SEMKEY, 1, 0777);
sem_oper.sem_num = PRINC;
sem_oper.sem_op = 1;
sem_oper.sem_flg = SEM_UNDO;
semop (semid, &sem_oper, 1);
} /* fin de main */
/* prinm.c
Descripcion: Este proceso crea una lista de semaforos y una region de memoria
para el proceso memoria.c. Una vez que este ultimo termina,
el proceso prinm.exe elimina la lista de semaforos y la region
de memoria.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define SHMKEY 70
#define SEMKEY 60
main ()
{
int semid,shmid;
struct sembuf sem_oper;
union semun arg;
struct shmid_ds *shmstatbuf;
Bloque 5: Programación con la interfaz del sistema. 125
sem_oper.sem_num = 0;
sem_oper.sem_op = -1;
sem_oper.sem_flg = SEM_UNDO;
semop (semid, &sem_oper, 1);
sem_oper.sem_num = 0;
sem_oper.sem_op = -1;
sem_oper.sem_flg = SEM_UNDO;
semop (semid, &sem_oper, 1);
/* Con esta operacion espero a que termine el proceso memoria.exe para
eliminar tanto la lista de semaforos como la region de memoria */
} /* Fin de main */
/* conmem.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHMKEY 70
main ()
{
int shmid,*pint;
char *addr;
} /* Fin de main */
Se debe ejecutar primero el programa prinm.c antes del programa memoria.c. Por último se
ejecuta el programa conmem.c. Todos estos programas deben ejecutarse en modo background.
PRÁCTICA:
Crear dos procesos que utilicen memoria compartida para comunicarse. Un proceso
introduce texto en la memoria compartida y el otro la lee de allí y la introduce en un archivo.
Bloque 5: Programación con la interfaz del sistema. 127
CONCEPTOS BÁSICOS:
struct hostent {
char *h_name; /* nombre oficial */
char **h_alias; /* lista de alias */
int h_addrtype; /* tipo de dirección */
int h_lenght; /* longitud de la dirección */
char **h_addr_list; /* lista de direcciones */
long h_addr; /* dirección IP */
};
La función getservbyname permite obtener el número del puerto local de un servicio a partir
del nombre del servicio. Para ello busca en el archivo /etc/services. Los argumentos que se le pasan a
la función son el nombre del servicio y la familia de protocolos.
La función devuelve un puntero a una estructura (servent) que contiene el número del puerto
requerido. Su formato es el siguiente:
struct servent {
char *s_name; /* nombre oficial del servicio */
char **s_aliases; /* lista de alias */
int s_port; /* número del puerto */
char s_proto; /* familia de protocolos */
char **h_sddr_list /* lista de direcciones */
};
Crear buzón:
Bloque 5: Programación con la interfaz del sistema. 128
Para poder crear los buzones se utiliza la función socket. Los argumentos que se le pasan son
la familia de protocolos (AF_INET), el tipo de comunicación (SOCK_STREAM ó
SOCK_DGRAM) y el protocolo específico que se va a usar (tcp o udp). La función devuelve un
entero que identifica al buzón recién creado.
La función bind enlaza una dirección a un buzón. Los argumentos que se le pasan son el
identificador del buzón que va a ser enlazado, un puntero a una estructura de dirección y el tamaño
de dicha estructura. El formato de una estructura de dirección es el siguiente:
struct sockaddr_in {
short sin_family; /* familia de dirección */
short sin_port; /* número de puerto */
long sin_addr; /* dirección IP */
…
};
Escuchar solicitudes:
La función listen solamente indica que la aplicación desea aceptar solicitudes de conexión.
Los argumentos que se le pasan son el identificador del buzón y el número máximo de solicitudes
pendientes en la cola (límite “backlog”).
Aceptar solicitudes:
Enviar/recibir información:
La función send se utiliza para enviar datos a un buzón conectado. Los argumentos que se le
pasan so el identificador del buzón, un puntero al buffer desde donde se va a enviar los datos y la
longitud del buffer de recepción.
La función recv se utiliza para leer datos desde un socket conectado. Los argumentos que se
le pasan son el identificador del buzón devuelto por la función accept, un puntero al buffer donde se
van a recibir los datos y la longitud del buffer de recepción.
Un proceso cliente necesita realizar las siguientes operaciones para poder solicitar servicios
por parte de un proceso servidor:
Crear un buzón:
La función socket permite crear buzones, de igual forma a como ocurría con el proceso
servidor.
La función connect permite a un cliente iniciar una conexión con el buzón de un servidor.
Los argumentos que se le pasan a la función son el identificador del buzón, un puntero a una
estructura de dirección y un puntero a un entero que contienen el tamaño de dicha estructura.
Enviar/recibir información:
Se utilizará las funciones send o recv según sea el flujo de información que interese.
Veamos un programa ejemplo que nos permita comprobar como se usan las llamadas al
sistema que permiten crear un modelo cliente/servidor.
/* cliente.c */
/* PROCESO CLIENTE */
main ()
{
/* declaracion de variables y estructuras de datos */
int retcode;
int sock;
int errno;
struct sockaddr_in name;
struct sockaddr_in addr;
struct servent *servrec;
struct hostent *hostrec;
char buf[40];
Bloque 5: Programación con la interfaz del sistema. 130
char host[30];
int flag=0;
/* Crear un socket */
if ((sock=socket (AF_INET, SOCK_STREAM, 0))==-1)
error (3);
/* Cerrar conexion */
if (close (sock)==-1) error (6);
} /* fin de main */
error (n)
int n;
{
switch (n) {
case 1: printf ("Error en gethostbyname \n");
break;
case 2: printf ("Error en getservbyname \n");
break;
case 3: printf ("Error en socket \n");
break;
case 4: printf ("Error en connect \n");
break;
case 5: printf ("Error en send \n");
break;
case 6: printf ("Error en close \n");
break;
} /* fin de switch */
exit (1);
} /* fin de error */
Bloque 5: Programación con la interfaz del sistema. 131
/* servidor2.c */
/* PROCESO SERVIDOR */
main ()
{
/* declaracion de variables y estructuras de datos */
int retcode;
int sock;
int newsock;
int len=0;
int flag=0;
struct sockaddr_in name;
struct sockaddr_in addr;
struct servent *servrec;
struct hostent *hostrec;
char buf[40];
char host[30];
/* Crear un socket */
if ((sock=socket (AF_INET, SOCK_STREAM, 0))==-1)
error (3);
/* Escuchar solicitudes */
if ((retcode=listen (sock, 1))==-1)
error (5);
Bloque 5: Programación con la interfaz del sistema. 132
/* Aceptar solicitudes */
memset (&addr, 0, sizeof (addr));
len = sizeof (addr);
if ((newsock = accept (sock, &addr,&len)) == -1)
error (6);
/* Recibir un mensaje */
if (retcode = recv (newsock, buf, sizeof (buf), 0) == -1)
error (7);
/* Cerrar conexion */
if (close (newsock)==-1) error (8);
if (close (sock)==-1) error (8);
} /* fin de main */
error (n)
int n;
{
switch (n) {
case 1: printf ("Error en gethostbyname \n");
break;
case 2: printf ("Error en getservbyname \n");
break;
case 3: printf ("Error en socket \n");
break;
case 4: printf ("Error en bind \n");
break;
case 5: printf ("Error en listen \n");
break;
case 6: printf ("Error en accept \n");
break;
case 7: printf ("Error en recv \n");
break;
case 8: printf ("Error en close \n");
break;
case 9: printf ("Error en send2 \n");
break;
} /* fin de switch */
exit (1);
} /* fin de error */
BIBLIOGRAFÍA
Brian W. Kernigham
El Entorno de Programación UNIX.
Prentice-Hall Hispanoamericana, S.A.
Maurice J. Bach
The Design of the UNIX Operating System.
Prentice-Hall Software Series.
Tema 1: Introducción.
Características principales.
Historia de UNIX.
El papel de C en UNIX.
Tema 4: Procesos.
Entorno de procesamiento.
Modos de ejecución.
Detención de procesos.
Tema 3: El Shell.
¿Qué es el Shell?
El shell Bourne (sh).
El shell C (csh).
El shell Korn (ksh).
El shell C mejorado (tcsh).
Procedimientos de shell o shell scripts.
Tema 5: Dispositivos.
Creación de dispositivos.
Tema 1: El compilador de C.
Compilación y ejecución de programas en C.
El compilador cc.
Tema 5: Semáforos.
Conceptos básicos.
Práctica.