SysV: El inicio de GNU/Linux y el caso de SysV init

Publicado por Diego Córdoba en

En este artículo continuaremos describiendo la secuencia de arranque de un sistema GNU/Linux. En el artículo anterior recorrimos desde que encendemos la computadora hasta que carga el núcleo Linux. Ahora veremos qué pasa después: los procesos de inicio, servicios del sistema, e interfaz de usuario. Particularmente hablaremos sobre SysV init.

Introducción

Ya vimos en el artículo anterior qué ocurre en la computadora desde que se enciende hasta que se carga el kernel Linux. En esta oportunidad hablaremos sobre qué es lo que ocurre después… básicamente, cómo se carga el resto del sistema operativo GNU/Linux, y qué procesos intervienen.

Una vez que se carga el núcleo Linux, el resto de los servicios del sistema se cargan utilizando varios mecanismos de inicio tales como el controversial systemd, el viejo y querido SysV init, o el olvidado Upstart creado por Canonical para su Ubuntu.

Una vez que el núcleo se ha lanzado, lo siguiente es cargar todos los servicios necesarios para que el sistema sea utilizable. Esta secuencia depende de qué gestor de servicios o de inicio esté utilizando nuestra distro GNU/Linux. En este artículo describiré el sistema de inicio del clásico System V (SysV init), y en el próximo hablaré sobre systemd.

Antes de entrar en tema, comento que este contenido es parte de la certificación internacional LPIC-1, por lo que sirve de documentación para aquellos alumnos de JuncoTIC que tomen el curso de Administración Linux para certificar.

SysV init

Tradicionalmente la funcionalidad del proceso init se ha incorporado a sistemas operativos Unix SystemV y BSD. SystemV es una de las versiones de Unix desarrollada originalmente por AT&T en 1983. Linux posteriormente adoptó la versión más popular de System V para su proceso de inicio. Esta versión fue la release 4, por lo que comúnmente puede encontrarse información etiquetada como SVR4 (System V release 4).

El proceso init para SysV es el primer proceso del sistema, y el encargado de velar durante toda la ejecución de un GNU/Linux. Su PID (Process ID) es el número 1. Originalmente en Unix el proceso init arrancaba los servicios mediante un único script denominado /etc/rc.

Luego este script fue reemplazado por un nuevo esquema de servicios y script escritos en el directorio /etc/rc.d/ en algunas distros y sistemas como Slackware, las versiones Sysv Init de Redhat, o el Unix FreeBSD. En otras como Debian los scripts de inicio se escriben en el directorio /etc/init.d/ y se referencian, mediante enlaces simbólicos en directorios /etc/rcN.d/. Además, en distros como Centos el directorio /etc/init.d no es más que un enlace simbólico a /etc/rc.d.

Con esto quiero decir que si bien todos estos sistemas utilizan el mecanismo de inicio SysV init, deberemos remitirnos a la documentación de cada distro para saber exactamente dónde se almacenan los scripts de inicio y sus configuraciones.

En general GNU/Linux adoptó el esquema SystemV, aunque algunas distros usaban esquemas de BSD, tales como Slackware, y otras distros como Gentoo tienen su propio gestor personalizado. Hoy muchas distros, incluidas Debian y RedHat adoptaron systemd para su secuencia de inicio y ejecución.

Secuencia de SysV

El proceso init al lanzarse luego de la carga del kernel Linux, toma sus configuraciones desde el archivo /etc/inittab, que especifica una secuencia de ejecución de scripts del sistema, y configuraciones de runlevels, o niveles de inicio del sistema operativo.

Antes de entrar en la secuencia de arranque es necesario que comprendamos qué son los runlevels, y qué papel cumplen dentro de un sistema que implementa SysV Init.

Runlevels

Los runlevels son modos de operación de un sistema GNU/Linux que utiliza SysV Init, es decir, cada runlevel proporcionará al sistema cierta funcionalidad y tiene una utilidad específica. Los runlevels, o niveles de ejecución de GNU/Linux, o modos de ejecución, son 7 en total, pero no todos son operativos, es decir, no en todos podemos trabajar con nuestra terminal y nuestros comandos.

En la siguiente tablea podemos ver una lista de los runlevels y su funcionalidad:

0Apagado del sistema
1Monousuario sin servicios de red. El único usuario que puede trabajar en este runlevel es root.
2Multiusuario sin servicios de red.
3Multiusuario con servicios de red. Este es el inicio normal en terminal.
4Runlevel no utilizado en general.
5Multiusuario con soporte de red e inicio gráfico (window manager). Este es el inicio gráfico más común.
6Reinicio del sistema
SNo en todas las distros SysV existe este runlevel. Es similar al runlevel 1, con la diferencia de que durante la ejecución podemos pasar a runlevel 1 con init, mientras que el runlevel S solamente puede ser cargado como consola del sistema si está configurado como runlevel por defecto en /etc/inittab (ver más adelante).

Como puede apreciarse, de esta lista los únicos runlevels operativos son el 1, 2, 3 y 5.

Podemos ver el runlevel utilizando el comando runlevel:

sysv runlevel

En esta captura se ve que estoy en un runlevel 5. La «N» indica el runlevel anterior en el que he estado. Si cambiamos de runlevel podremos ver el anterior y el nuevo en esa salida. En el caso de que el sistema inicie en un runlevel y no lo cambiemos a la hora de ejecutar el comando runlevel, el runlevel anterior será «N«.

Por supuesto, de más está decir que esta salida corresponde a un sistema que utiliza SysV init, o systemd pero posee las bibliotecas de compatibilidad con SysV Init, como es el caso de este Debian 10.2.

Configuraciones de SysV e inittab

Si el sistema usa SysV Init, poseerá un archivo de configuración de inicio denominado /etc/inittab.

En dicho archivo veremos, entre otras líneas de configuración que no vienen al caso en este momento, algo similar a esto:

id:3:initdefault:

Esa línea indica que el runlevel por defecto al iniciar el sistema es el 3 (inicio en multiusuario modo texto). Esto indica que el sistema, ni bien se inicie el kernel, arrancará en runlevel 3 (o el que indiquemos en dicha línea de configuración).

Tareas de inicialización de SysV init

El primer script que init ejecuta es /etc/rc.d/rc.sysinit, que lleva a cabo varias tareas de inicialización tales como:

  • Iniciar el daemon devfs si es utilizado.
  • Montar el sistema de archivos /proc
  • Mostrar el mensaje de bienvenida en la consola.
  • Desmontar el initrd lanzado en la secuencia de inicio.
  • Configurar el reloj del sistema.
  • Configurar el hostname.
  • Inicializar el bus usb.
  • Verificar y correr fsck si corresponde (si el sistema se apagó anormalmente, o si pasaron N cantidad de montajes de los dispositivos desde el último fsck.
  • Remontar el sistema de archivos raíz en modo lectura/escritura.
  • Iniciar LVM si corresponde.
  • Inicializar /etc/mtab.
  • Cargar, si existe, /etc/rc.modules
  • Montar los sistemas de archivos no root.
  • Iniciar en gestor gráfico.
  • Verificara quotas de disco.
  • Eliminar archivos lock
  • Iniciarlizar puertos seriales, scsi y dispositivos USB.
  • Iniciar el firewall del sistema.

Luego, siempre siguiendo los lineamientos configurados en /etc/inittab, es lanzar /etc/rc.d/rc pasándole un número que representa un runlevel. Ese runlevel inicial que utilizará el sistema para arrancar está especificado en el archivo inittab.

Administrando rc

El proceso rc puede ser re-ejecutado por un administrador luego de que el inicio del sistema halla llegado a su fin, simplemente cambiando el runlevel utilizando el binario /sbin/init y pasándole por argumento el nuevo runlevel. Hay que notar que este programa init es el mismo que se ejecuta al iniciar el sistema. Si el proceso init corre con el PID=1 es el encargado de llevar a cabo todas las tareas del inicio y gestión del sistema, mientras que si corre con un PID distinto de 1 es un proceso lanzado durante la ejecución de GNU/Linux por un administrador, y simplemente le enviará una señal con el nuevo runlevel al proceso init que se está ejecutando.

Cuando el administrador ejecuta un init con un runlevel distinto del actual (puede verse el runlevel actual ejecutando el comando runlevel) el proceso init ejecutará todos los scripts cuyo nombre comience con «K» que se encuentren dentro del directorio /etc/rcX.d/, donde «X» representa el número de runlevel actual (no el pasado a init).

Acto seguido, ejecutarán todos los scripts cuyo nombre comience con «S» que se encuentren dentro del directorio /etc/rcN.d/, donde «N» representa el nuevo runlevel pasado al proceso init.

Lanzando y deteniendo servicios

Para administrar un servicio, imaginemos, postfix, usando SysV en general se utiliza un comando como este:

sudo /etc/init.d/postfix comando

Donde «comando» puede ser:

  • start: para iniciar el servicio
  • stop: para detener el servicio
  • restart: para reiniciar el servicio (detenerlo y volver a iniciarlo)
  • reload: para recargar la configuración (en general se le envía la señal HUP (1) al proceso que da vida al servicio).
  • status: para ver información del servicio.

Si bien estos son comandos comunes, puede que algunos servicios no soporten algunos, o que incorporen otros comandos puntuales.

Los servicios que iniciemos se cargarán en la ejecución local del sistema, independientemente de en qué runlevel estén configurado… es decir, si el servicio postfix solamente está configurado para iniciarse por defecto en runlevel 3, y arrancamos la computadora en runlevel 5, postfix no iniciará, pero eso no quita que podamos iniciarlo manualmente con el comando start.

Cargando y descargando scripts de inicio

En general, en el primer caso (scripts cuyo nombre comienza con «K» de «kill») recibirán un parámetro «stop«, mientras que en el segundo (scripts cuyo nombre comienza con «S» de «start») recibirán un «start» en el momento de ejecutar el init con un runlevel determinado.

Todos los scripts de inicio de servicios se encuentran dentro de /etc/init.d. Los archivos que vemos en /etc/rcX.d/ son enlaces simbólicos a archivos dentro de /etc/init.d (X es el número de runlevel).

Los nombres de los servicios en general van precedidos por la «S» o la «K» según corresponda, y un número que indica el orden o prioridad de lanzamiento del script. El que tenga una «S» y un número más pequeño será el primero en lanzarse.

La prioridad por defecto es 20, aunque podemos especificar una distinta. Un número menor indica una mayor prioridad, es decir, los script que tengan un número más pequeño serán los primeros en lanzarse cuando inicie el sistema (tenerlo en cuenta por dependencia de servicios), y serán los últimos en apagarse cuando el sistema se apague.

Usando update-rc.d

Si Queremos desactivar un script de inicio para un runlevel determinado, suponiendo, «N», deberemos dirigirnos al directorio /etc/rcN.d/ y ver si existe un symlink para el script correspondiente. En el caso de que exista y esté en «K», podemos modificar la «K» por una «S» manualmente. Si no existe, podremos crear un symlink manualmente con el comando «ln«, aunque lo mejor siempre es utilizar utilidades creadas a tal efecto, como update-rc.d.

Así, suponiendo que el servicio se denomina «postfix» por ejemplo, podremos habilitarlo para todos los runlevels usando:

sudo update-rc.d postfix defaults

Y podremos eliminarlo con:

sudo update-rc.d -f postfix remove

Esto es para habilitar o deshabilitar un servicio al inicio del sistema para todos los runlevels. Para cargarlo con una prioridad distinta de 20, podemos hacer esto:

sudo update-rc.d postfix defaults 50

Esta línea creará los enalces con prioridad 50… el nombre de los enlaces será algo así (para cada runlevel):

/etc/rc0.d/K50postfix -> ../init.d/postfix
/etc/rc1.d/K50postfix -> ../init.d/postfix
/etc/rc6.d/K50postfix -> ../init.d/postfix
/etc/rc2.d/S50postfix -> ../init.d/postfix
/etc/rc3.d/S50postfix -> ../init.d/postfix
/etc/rc4.d/S50postfix -> ../init.d/postfix
/etc/rc5.d/S50postfix -> ../init.d/postfix

Y podemos ir un poco más allá… podemos iniciar el servicio en una prioridad u orden, y apagarlo en otra especificando ambas en línea de comandos:

sudo update-rc.d postfix defaults 50 80

Lo que generará algo similar a esto:

/etc/rc0.d/K80postfix -> ../init.d/postfix
/etc/rc1.d/K80postfix -> ../init.d/postfix
/etc/rc6.d/K80postfix -> ../init.d/postfix
/etc/rc2.d/S50postfix -> ../init.d/postfix
/etc/rc3.d/S50postfix -> ../init.d/postfix
/etc/rc4.d/S50postfix -> ../init.d/postfix
/etc/rc5.d/S50postfix -> ../init.d/postfix

El servicio se iniciará en prioridad 50 en los runlevels operativos, y se apagará en prioridad 80 en los de reinicio y apagado del sistema, y en el de single user.

Y por si fuera poco, también podemos iniciar o apagar un servicio con distintas prioridades en distintos runlevels… aquí un ejemplo:

update-rc.d postfix start 20 2 3 4 . start 30 5 . stop 80 0 1 6 .

Este comando habilitará por defecto al servicio postfix en los runlevels 2, 3 y 4 con la prioridad 20, en el runlevel 5 con la prioridad 30, y utilizará la prioridad 80 para apagar el servicio (stop) en los runlevels 0, 1 y 6… simple no? xD

Conclusiones

Hemos aprendido cómo funciona el inicio de un sistema GNU/Linux que haga uso de SysV init, como Devuan o Etertics. Aprendimos sobre los conceptos de runlevels, scripts de inicio, y también sobre comandos y herramientas para administrar un servicio en consola, o para configurar su inicio y detención en diferentes prioridades en diferentes runlevels.

En el siguiente artículo veremos los detalles del inicio en distros que usen systemd.

Hasta la próxima!

Categorías: Linux

Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador