Upstart: runlevel desde grub

Modificando upstart para elegir un nivel

u otro de arranque desde grub

J. Félix Ontañón Carmona <felixonta desde gmail.com>

 

El siguiente documento se cede al dominio público, según la licencia

CC Reconocimiento-NoComercial-CompartirIgual 2.5 España

 




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.



Requisitos

Ubuntu Edgy, Feisty o superior, o cualquier distribución que use Upstart
como demonio init funcionando como wrapper (envoltorio) a SysVinit.

Grub como Boot Loader.



El efecto conseguido

Podemos indicar el runlevel con el que arrancar indicándolo como parámetro
en el comando de entrada de menú kernel de Grub:

  • Escribiéndolo directamente en el fichero /boot/grub/menu.lst

  • En boot-time desde el menú de Grub usando la línea de comandos de éste.

Aquí un ejemplo de como quedaría una entrada de menú Grub que arranca en runlevel 3

  
  title           Ubuntu, kernel 2.6.17-11-386
  root            (hd0,0)
  kernel          /boot/vmlinuz-2.6.17-11-386 root=/dev/sda1 ro quiet splash runlevel=3
  initrd          /boot/initrd.img-2.6.17-11-386
  savedefault
  boot
  
 


Procediendo

Sustituir el fichero /etc/event.d/rc-default por lo 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
  
  


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.



Posibilidades

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

Línea de comandos de Kernel

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

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.



Fichero /etc/event.d/rc-default

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.



Capítulo 4. Bibliografía

Espero que este humilde artículo haya sido de vuestro agrado y podáis sacar mas partido a los niveles de arranque. Para mas información:

Enviado por Felix el Lun, 2007-08-06 22:14. añadir nuevo comentario
Enviado por Anonymous el Dom, 2007-12-09 21:20.

Muy buen artículo!! llevaba tiempo buscando acerca de los runlevels, y encontraba poca info. y un poco engorrosa. He dado con tu artículo y me ha calado. Claro, simple y al grano, algo muy dificil de encontrar por la web.

Felicidades y muchas gracias por compartir, en este caso, sabiduría.

Saludos desde Canary Island.

Enviado por Felix el Mar, 2007-12-18 23:29.

Sucede que con Ubuntu a día de hoy la gestión del demonio init ha cambiado a causa de upstart, por mucho que lo hayan hecho retrocompatible y tal.

No obstante la gestión de upstart permite perlas como las que comento en el artículo.

Se agradecen tu opinión !!