Capítulo 1. Guía Rápida
Para los impacientes y para los que conocen la intención de este documento no me andaré por las ramas y explicaré la solución porpuesta.
Capítulo 2. Motivación
Sabemos que como estándar de facto se usan 8 niveles de incio con SysVinit: desde rc0 a rc6 mas rcS. De esos niveles de inicio 3 son reservados:
0. Halt
1. Single-mode user
6
. Reboot
El resto de niveles de inicio, son los llamados user
-definible runlevels.
A lo largo del tiempo los administradores de sistemas han sacado partido a estos runlevels definiendo que procesos iniciar o parar en cada uno de ellos para conseguir llevar a la máquina a uno u otro estado. Las distribuciones también han hecho uso de estos niveles para definir que niveles de arranque multiusuario, con o sin entorno gráfico, por ejemplo.
No obstante las distribuciones mas orientadas a escritorio han ido despreocupándose progresivamente de la utilidad que niveles de arranque pueden tener para sus usuarios finales, de modo que, algo tan particular como la elección de un nivel de arranque u otro en boot
-time
parece haber caido en el olvido y la documentación al respecto es realmente escasa.
Mas aún, con la prometedora llegada de Upstart, por parte de Ubuntu
desde su versión 6
.10 (Edgy Eft), y los cambios que esta trae consigo, la información buscada es nula.
La imaginativa configuración de los niveles de inicio sumado a la posibilidad de seleccionar uno u otro en tiempo de arranque abre un mundo de posibilidades no solo destinado a los administradores de sistemas sino también a usuarios de escritorio.
Esta podría ser una curiosa propuesta:
Runlevel 2: Arranque por defecto.
Modo multiusuario con entorno gráfico. Un runlevel con la configuración por defecto de la distribución.
Runlevel 3: Media
Center.
Modo monousuario que inicia lo mínimo necesario arrancar a pantalla completa un media
center (o multimedia center) como Freevo, Elisa o Linux
Media
Center (LMC).
Runlevel 4: Modo ahorro de recursos
.
Iniciar el sistema librándonos de la mayoría de servicios
pesados con el fin
de tener un sistema con los mínimos recursos
consumidos. Ideal para jugones.
Para cada nivel se podría crear una entrada de menú en Grub que el usuario podría elegir.
Capítulo 3. Explicación paso a paso
El núcleo puede aceptar parámetros en tiempo de arranque. Un par de parámetros populares que sirven para ilustrarnos son:
root
=/dev
/dispositivo
vga=ext
Una vez montado el sistema de ficheros virtual proc
podemos ver los parámetros pasados como argumento en la línea de comandos del kernel
en /proc
/cmdline.
En la actualidad la línea de comandos del núcleo es también usada indicar otras opciones de arranque. InitramFS (imagen initrd
) parsea la línea de comandos en busca de parámetros, y así, por ejemplo, se procede a la identificación de unidades de disco por UUID.
En este caso hemos definido un nuevo parámetro en la kernel
cmdline con el acertado nombre runlevel
Upstart es un init daemon
creado por el Ubuntu
-team
que pretende ser sustituto del init de System
V. Es el único proceso que arranca el núcleo y encargado de llamar al resto de programas/servicios
del sistema. En Linux
, todo proceso es hijo de init.
Ciertamente Upstart presenta interesantes mejoras respecto del init de System
V: Arranque de servicios en paralelo, guiado por eventos, servicios
que se rearrancan automáticamente si mueren, etc ... Sin embargo, por el momento (este documento fue escrito en Agosto 2007) las únicas distribuciones que lo implementan son Ubuntu
(Edgy/Feisty) y Debian
Experimental. Es mas, toda la potencia de Upstart no es aprovechada pues, por retrocompatibilidad con los scripts
de sysvinit, upstart solo se acaba comportando como un wrapper
de éste.
En /etc/event
.d/ tenemos los ficheros de configuración de upstart que, podríamos decir, funcionan como si del fichero /etc/inittab se tratase:
Ficheros ttyX: que llaman a la creación de las terminales con getty.
Ficheros rcX: que acaban ajustando el runlevel y llamando a /etc/init.d/rc
para ejecutar los scripts
del nivel de arranque correspondiente.
Otros ficheros como ctrl-alt-del que mapea dicha combinación al reincio ordenado del equipo, o rc
-default
que define el nivel de inicio por defecto.
Es este último fichero, rc
-default
, es el objeto de nuestro estudio
.
Originalmente, Ubuntu
Edgy y Feisty, define este fichero como sigue:
# rc - runlevel compatibility # # This task guesses what the "default runlevel" should be and starts the # appropriate script .
start on rcS/stop script runlevel --reboot || true
if grep -q -w -- "-s\|single\|S" /proc /cmdline; then telinit S elif [ -r /etc/inittab ]; then RL="$(sed -n -e "/^id:[0-9]*:initdefault:/{s/^id://;s/:.*//;p}" /etc/inittab || true)" if [ -n "$RL" ]; then telinit $RL else telinit 2 fi else telinit 2 fi end script
|
Aquel que conozca bash
-scripting
puede darse cuenta rápidamente que el script
busca en la línea de comandos del núcleo la directiva
single para arrancar en single-mode user
, caso contrario busca en /etc/inittab el runlevel por defecto (retrocompatibilidad con sysvinit) y si no hay ninguno definido se toma el runlevel 2 como nivel de inicio.
Vemos pues que incluso este script
parsea la línea de comandos del kernel
, en busca de parámetros para iniciar el single-user
mode, si procede. No es, por tanto, mucho mas dificil imaginar como modificar dicho script
para que se parsee la línea de comandos del núcleo en busca de nuestro parámetro runlevel.
La aproximación seguida, aunque no la mejor, es la siguiente:
# rc - runlevel compatibility # # This task guesses what the "default runlevel" should be and starts the # appropriate script . # # (c) J. Félix Ontañón 2007. Distribuido con licencia GPLv2 # # Modificado para correr uno u otro nivel de inicio según lo que indique el # parámetro "runlevel" pasado al kernel por la cmd-line en tiempo de arranque. # start on rcS/stop
script runlevel --reboot || true
RUNLEVEL=2
for x in $(cat /proc /cmdline); do case $x in runlevel=*) RUNLEVEL=${x#runlevel=} ;; esac done
telinit $RUNLEVEL
end script
|
Sencillo y funcional: extrae el nivel de arranque de la línea de comandos del núcleo y ajusta el runlevel 2 por defecto. Podríamos complicarlo un poco mas determinando el nivel de arranque por defecto extrayéndolo del /etc/inittab si hubiere.
Además, por haberse construido con un bloque case
este script
es fácilmente extensible para añadir nuevos parámetros.