Software">
01 Material de Lectura 101
01 Material de Lectura 101
01 Material de Lectura 101
Conociendo el sistema
En Linux "todo es un archivo" reza el dicho. En otras palabras, cada componente del
sistema puede ser manipulado como si fuera un archivo común y corriente en el
sentido de que se puede leer y escribir en él. Como ejemplo podemos citar a los
comúnmente llamados pseudo sistemas de archivos. Lejos de tratarse de dispositivos
reales donde podemos almacenar información variada, en realidad consisten en una
especie de ventana que nos permite acceder (leer) a información del sistema de una
manera relativamente amigable.
El directorio /proc
Según el Filesystem Hierarchy Standard, el directorio /proc es el método adecuado
para obtener información sobre el sistema ya que en el mismo se encuentra montado
el pseudo sistema de archivos proc. Además, en este directorio también encontraremos
datos sobre los procesos que están corriendo actualmente.
Al ingresar a /proc lo primero que nos llama la atención es que hay varios directorios
cuyo nombre es un número (1, 10, 12, 13, 606, etc.). Dicho número es el identificador
de un cierto proceso y cada subdirectorio dentro del mismo contiene información
asociada a dicho proceso. Cuando un proceso finaliza su ejecución, o es terminado, su
directorio asociado dentro de /proc desaparece.
Supongamos que deseamos inspeccionar más en detalle el proceso cuyo identificador
es 541. Para ello nos posicionamos en el directorio /proc/541 donde encontraremos
los siguientes archivos de interés (entre otros):
• cmdline: contiene los argumentos de la línea de comandos que se utilizaron para
iniciar el proceso.
Como podemos ver, sysfs provee datos que también están disponibles a través de
proc, aunque de una manera más estructurada.
Udev y el directorio /dev
Dentro de la estructura de directorios en Linux, los dispositivos presentes en el equipo
pueden observarse dentro del directorio /dev a partir de los datos presentes en /sys.
En esa ubicación encontraremos archivos que representan discos (incluyendo
particiones, grupos de volúmenes, y volúmenes lógicos), memoria, terminales, y otros.
En primer lugar, cuando se agrega o quita un dispositivo (o cambia su estado de
alguna forma) del sistema, el kernel lo informa al servicio systemd-udevd a fin de
prepararlo para su uso. Este último puede configurarse para responder a dichos
eventos mediante reglas en archivos con la extensión .rules dentro de los siguientes
directorios:
• /etc/udev/rules.d
• /run/udev/rules.d
• /usr/lib/udev/rules.d
Si existen archivos con nombres iguales, la prioridad más alta es dada a aquellos
dentro de /etc/udev/rules.d, seguida por /run/udev/rules.d, y luego por
/usr/lib/udev/rules.d. Como resultado, podemos identificar un dispositivo
basándonos en sus propiedades y sin importar el puerto de conexión o el orden en
que haya sido descubierto, podemos asignarle un nombre fijo.
Es importante mencionar que se dispone de udevadm, una herramienta para controlar
el funcionamiento de udev. Entre sus usos útiles, podemos destacar udevadm monitor
--kernel que muestra los eventos detectados por el kernel. Luego de ejecutar este
comando, tendremos que esperar a que se registre un cambio. A continuación,
podremos ver el detalle por la salida estándar. En la imagen siguiente observamos la
detección de un dispositivo USB conectado al equipo luego de ejecutar el comando:
Además del uso ilustrado en la imagen anterior, udevadm nos sirve para administrar la
lista de eventos en espera (udevadm settle y udevadm control) y nos permite
simular eventos (udevadm test) y debuguearlos.
Finalmente, para que una aplicación de escritorio envíe o reciba mensajes de otra
aplicación (o del kernel mismo) existe un mecanismo de comunicación llamado D-
Bus. Por ejemplo, cuando insertamos un dispositivo de almacenamiento extraíble,
udev envía un mensaje a través de D-Bus al gestor de ventanas para que muestre una
notificación por pantalla o provea un ícono de acceso directo al dispositivo.
Comandos útiles
Además de los ejemplos que mencionamos anteriormente, existen numerosas
herramientas que nos permiten examinar la operación del kernel y el estado de los
dispositivos conectados a nuestro equipo. A continuación, veremos un listado de las
más conocidas.
Para removerlo:
modprobe -r ac97_bus
Tengamos en cuenta que modprobe nos permite insertar o remover módulos, pero
dichos cambios no son permanentes; es decir que se pierden al reiniciar el equipo.
Para lograr que un módulo en particular se cargue al inicio del sistema, debemos
agregar el nombre del módulo en el archivo /etc/modules-load.d/modules.conf.
También es posible crear archivos separados con la extensión .conf dentro del mismo
directorio.
Por ejemplo, para cargar el módulo virtio-net.ko podríamos crear el archivo
/etc/modules-load.d/virtio-net.conf con el siguiente contenido (las líneas que
comienzan con # se consideran comentarios y son ignoradas):
# Load virtio-net.ko at boot
virtio-net
lspci
lspci -v
Además de estas herramientas, también podemos utilizar lsblk para ver todos los
dispositivos de bloques en forma de árbol. De esta manera tenemos la posibilidad de
ver las particiones de cada disco y los volúmenes lógicos, por nombrar dos ejemplos:
En la imagen de arriba podemos ver que sda posee 3 particiones (sda1, sda2, y sda5).
En una de ellas (sda5) reside el grupo de volúmenes llamado debianhome-vg y
dentro del mismo encontramos los volúmenes lógicos root, var, swap_1, tmp, y
home.
Dispositivos USB
En el archivo /var/lib/usbutils/usb.ids podemos encontrar una lista de dispositivos
USB por fabricante. El comando lsusb utiliza la información disponible en dicho
archivo para identificar la lista de dispositivos USB y sus buses de conexión presentes
en nuestro equipo. Estos datos pueden ser actualizados descargando la última versión
desde http://www.linux-usb.org/usb.ids.
En la imagen siguiente vemos la salida típica de este comando:
Para mostrar más detalles podemos utilizar las opciones -v o -vv, tal como en otros
comandos mencionados anteriormente.
La secuencia de arranque
Al encender el equipo, el BIOS (Basic Input-Output System) o UEFI (Unified
Extensible Firmware Interface) llevan a cabo una revisión del hardware conocida
comúnmente como POST (Power-On Self Test). A continuación, se busca un gestor de
arranque (por lo general, GRUB) en el MBR (Master Boot Record) o en la partición
EFI de un dispositivo de almacenamiento.
A partir de ese momento, el control del proceso se pasa a manos de GRUB, que se
encargará de cargar el kernel, el cual reconocerá y configurará los dispositivos de
hardware presentes en el equipo y los preparará para su uso. Como próximo paso, el
núcleo también será responsable por ejecutar el primer proceso, también conocido
como init. Finalmente, este último utilizará el gestor del sistema (systemd o Upstart)
o los scripts de SysVinit para continuar el inicio de los demás servicios. El proceso de
arranque culmina al presentar una interfaz de inicio de sesión de modo texto o gráfico,
según sea el caso.
Ahora hagamos un repaso por los 3 métodos de gestión del sistema más utilizados a lo
largo del tiempo.
SysVinit
Hasta no hace mucho tiempo, la mayoría de las distribuciones más utilizadas
utilizaban como base de su funcionamiento el sistema de arranque y de
administración de servicios conocido como SystemV o SysVinit. Este sistema,
heredado de Unix, contempla 5 niveles útiles de funcionamiento (de ahí el nombre
SystemV, correspondiente al número 5 en el sistema romano) numerados del 1 al 5. A
estos se les suma el nivel 0 (apagado del equipo) y el 6 (reinicio del sistema). Cada uno
de ellos es lo que se conoce como niveles de corrida o runlevels en Linux.
Cada runlevel se encuentra asociado a un cierto número de servicios que por defecto
deben iniciarse automáticamente cuando encendemos el equipo, y que deben
detenerse al reiniciarlo o apagarlo. Por ejemplo, en el directorio /etc en un sistema
Debian Wheezy podemos encontrar 7 directorios con nombre rcN.d, donde N es un
número del 0 al 6. Es precisamente dentro de estos directorios que se encuentran una
serie de enlaces simbólicos a los ejecutables que inician y detienen los servicios del
sistema en cada runlevel respectivo, como vemos a continuación:
Es importante tener en claro que lo primero que hace init es leer el archivo
/etc/inittab para identificar los próximos pasos a seguir. Por brevedad, nos
referiremos solamente a la detección del runlevel por defecto, lo que se indica en la
siguiente línea (2 en este ejemplo):
# The default runlevel.
id:2:initdefault:
El comando anterior hará que init se dirija al nivel de corrida 5 siguiendo el mismo
proceso que explicamos antes.
• Cualquier evento posterior al inicio del equipo necesita intervención manual del
usuario (identificación y montaje de dispositivos extraíbles, por nombrar dos
ejemplos).
Upstart
Entre SysVinit y la adopción final de systemd por la mayoría de las distribuciones
principales GNU/Linux, surgió una alternativa conocida como Upstart. Fue
desarrollada por Canonical (la empresa detrás de Ubuntu) e integrada por primera
vez con Ubuntu 6.10 Edgy a fines de 2006. Posteriormente, Fedora la adoptó y utilizó
hasta la versión 14 inclusive. Hoy en día podemos encontrarla en RHEL 6.7 y
similares, los cuales gozan de soporte hasta fines de 2018.
Upstart se pensó como un reemplazo basado en eventos para SysVinit. Como tal,
supervisa tareas mientras el sistema está funcionando y responde a eventos tales
como la conexión o desconexión de dispositivos extraíbles. Además, también gestiona
los servicios durante el inicio y el apagado. Es importante notar que es 100%
compatible con los scripts clásicos de SysVinit. De esta manera, aquellos servicios que
provean un script para init pueden funcionar sin problemas bajo Upstart.
Por otro lado, Upstart también trabaja con archivos .conf dentro del directorio
/etc/init. En los mismos se define el funcionamiento de servicios, y tienen la siguiente
estructura: - Descripción del proceso
• Niveles de corrida en los cuales el proceso debe ejecutarse o eventos que deben
iniciarlo.
• Niveles de corrida en los cuales el proceso no debe correr o eventos que deben
detenerlo.
• Opciones
Systemd
Es importante aclarar que systemd no surgió como un reemplazo de SysVinit porque
este último fuera defectuoso o porque hubiera usuarios y administradores que
estuvieran descontentos con el mismo. Más bien, comenzó como un proyecto para
desarrollar un sistema que fuera más eficiente al 1) iniciar menos servicios durante el
arranque (solamente aquellos que fueran estrictamente necesarios de acuerdo al uso
esperado y al hardware disponible), y 2) hacerlo en paralelo, en vez de manera
secuencial. En otras palabras, se buscó un sistema de inicio y de administración de
servicios que pudiera reaccionar dinámicamente ante cambios en el software y en el
hardware.
Targets en systemd
Bajo systemd, el concepto de runlevel o nivel de corrida solamente se mantiene por
compatibilidad con SysVinit. El componente básico de systemd se denomina unidad
(unit). Existen varias categorías de unidades: las más conocidas se denominan
servicios (services) y objetivos (targets). Las primeras son las que ejecutan los
daemons y sus dependencias en el orden apropiado. Por otro lado, las segundas se
utilizan para agrupar varias unidades. Estas últimas pueden compararse en cierta
forma a los clásicos runlevels.
Dentro de /lib/systemd/system podemos encontrar las definiciones de las distintas
unidades. Para empezar, cabe aclarar que los archivos de configuración de los targets
llevan el sufijo .target. Por ejemplo, podemos encontrar basic.target y multi-
user.target. Este último es el objetivo donde se encuentran agrupados la mayoría de
los daemons. Para funcionar correctamente, se necesita que basic.target esté
activado. Dicho de otra forma, antes de entrar en multi-user.target, todos los
servicios agrupados en basic.target deben haberse iniciado. A su vez, basic.target
requiere sysinit.target.
Además, en systemd hablamos de objetivo por defecto para describir el estado que
alcanza el sistema al finalizar el proceso de arranque. Para ver cuál es el objetivo por
defecto en nuestro sistema, podemos utilizar el comando
systemctl get-default
¿De dónde proviene este dato? Se trata de un enlace simbólico llamado default.target
dentro de /lib/systemd/system que apunta a la definición del target indicado. Por
ejemplo, en la imagen siguiente podemos ver que
/lib/systemd/system/default.target es un soft link hacia
/lib/systemd/system/graphical.target:
Por supuesto, es posible cambiar el target por defecto si es necesario. Por ejemplo,
para cambiar el objetivo por defecto a graphical.target (entrará en efecto con el
próximo reinicio), debemos recurrir a:
systemctl set-default graphical.target
Además, para controlar el inicio y los servicios del sistema, en distribuciones que
utilizan systemd se dispone de una herramienta llamada systemctl.
o
systemctl emergency
Logs de inicio
A fin de investigar inconvenientes cuando se produzcan, a menudo recurriremos a los
registros de operación (también llamados logs) del sistema. Mediante el comando
dmesg (diagnostic msg) podemos acceder a los mensajes emitidos por el kernel a lo
largo de la secuencia de arranque hasta el momento actual.
Por motivo de que cuando ejecutamos dmesg sin opciones se muestran todos los
mensajes, por lo general resulta útil aplicar un paginador como less, un filtro como
head o tail (para ver los primeros o los últimos registros), o utilizar grep para
identificar los resultados que cumplen con un patrón. Con respecto a esta última
alternativa, en el ejemplo que aparece a continuación veríamos solamente los
mensajes relativos a los dispositivos USB:
dmesg | less
dmesg | grep -i usb
Además de dmesg, systemd provee una utilidad llamada journalctl para acceder al
registro de eventos de arranque (y de otras clases también). Con journalctl --boot
podemos acceder a los datos correspondientes a un booteo en particular. La lista de
inicios para los que se dispone de información puede verse reemplazando --boot con
--list-boots. En la imagen siguiente podemos apreciar el resultado, donde -0 se
utiliza para indicar el booteo indicado como 0. En este caso se trata del inicio actual:
journalctl --list-boots
journalctl --boot -0 | head -n 5
journalctl --boot -0 | tail -n 5
Además, journalctl admite opciones que nos permiten ver datos de unidades
específicas. Por ejemplo, con la opción --unit=UNIT podemos visualizar datos de la
unidad representada por UNIT. Es decir, el comando
journalctl --unit=cron --boot
nos devolverá la lista de registros relacionados con cron durante el inicio del sistema.
Por otro lado, si nos interesa mostrar los eventos de una prioridad dada únicamente,
tenemos a nuestra disposición la opción --priority. Al indicar un nivel de prioridad
veremos los mensajes correspondientes al mismo y a todos los menores. Por ejemplo,
journalctl --boot --priority=4
nos mostrará los mensajes de nivel 4 (warning) hasta 0 (emerg), si los hubiere.
Las alternativas para reiniciarlo son similares (la primera se incluye por
compatibilidad hacia atrás con el runlevel 6):
init 6
reboot
shutdown -r [CUANDO] [MENSAJE OPCIONAL]
Bajo SysVinit, la utilización de shutdown traía aparejada la ventaja de que los procesos
que estuvieran corriendo se detenían correctamente, y los sistemas de archivos se
desmontaban prolijamente, a diferencia de las otras opciones que provocaban un
apagado abrupto del equipo. Por otra parte, bajo systemd todos los comandos
anteriores son sinónimos, y constituyen enlaces simbólicos al propio sistema de inicio
o a systemctl.
De todas maneras, tanto en el caso de apagar como para reiniciar el equipo, la ventaja
de usar shutdown consiste en poder indicar el momento en el que se realizará la acción
deseada (now para ahora, o una hora específica en el formato de 24 hs HH:MM) y
enviar un mensaje (opcional) para alertar a los usuarios que estén conectados al
sistema.
Por ejemplo, el siguiente comando
shutdown -r 14:00 'El sistema se reiniciará a las 14 hs'
enviará el mensaje entre comillas a los usuarios que estén conectados y agendará el
reinicio del sistema para las 14:00 hs.
Si existe un apagado pendiente y deseamos cancelarlo, podemos utilizar la opción -c
para tal fin:
shutdown -c 'El apagado ha sido cancelado. Puede continuar trabajando nor
malmente.'
Cuando hay un apagado o reinicio agendado o en curso no es posible iniciar nuevas
sesiones de usuario. Si es cancelado, se levantará esa restricción.
Es importante aclarar que usuarios con privilegios limitados también pueden escribir
a las terminales de otros usuarios siempre y cuando estas últimas lo acepten. Sin
embargo, no podrán evitar el banner con la opción -n, cosa que solamente el
superusuario puede hacer.