SDB:Cómo crear scripts de inicio de forma normalizada

Saltar a: navegación, buscar


Icon-obsolete.png Este artículo hace referencia a la versión '{{{1}}}' y ahora está obsoleto.

Mira en la página de discussion del artículo para más información.
Si sigue obsoleto, podría ser eliminado. Si es posible, por favor ayuda a actualizar el artículo para hacerlo actual.


Situación

  • En ciertas ocasiones, necesitas crear tus propios scripts de arranque (init scripts), de forma que arranquen o no cierto demonio dependiendo del nivel de ejecución del sistema (runlevel).
  • Te gustaría controlar cierto script haciendo uso de:

rc<nombredescript> {start|stop|status|reload|force-reload|try-restart|restart}

En este artículo se explicará cómo lograr esto, explicando además detenidamente todas las opciones de las que disponemos.

Procedimiento

El procedimiento es de lo más simple. Consta de 4 pasos simples:

  1. Copia la plantilla de init script que viene con openSUSE con el nombre que quieras darle:
cp /etc/init.d/skeleton /etc/init.d/<nombredescript>
  1. Edita el archivo /etc/init.d/<nombredescript> con algún editor de texto (como nano o kate) y lee y sigue las indicaciones.
  2. Activa ahora tu script para que pueda ser arrancado en el arranque del sistema:
insserv /etc/init.d/<nombredescript>
  1. Finalmente, crea un enlace a /sbin:
ln -s /etc/init.d/<nombredescript> /sbin/rc<nombredescript>

Profundizando

Los pasos arriba mencionados son los necesarios para hacerte tu propio script de arranque, a continuación se detalla con más atención cuál sería la forma estricta de diseñar un script de arranque, de forma que podamos, por ejemplo, poder redistribuirlo luego en otro openSUSE; o en otro sistema Linux que respete también el estándar definido por la LSB (Linux Standard Base). Dicho estándar viene definido en el siguiente documento Enlace en inglés

Nomenclatura

Los nombres de los scripts de arranque deben cumplir el estándar marcado por la LSB, debiendo estar listado aquí Enlace en inglés. Para registrar un nuevo nombre de script, sigue el procedimiento que se explica aquí.

NOTA: Si no quieres llegar tan lejos, simplemente comprueba que el tuyo al menos no coincida con alguno de la lista, de esta forma evitarás posibles futuros conflictos.

Estructura

La estructura de un script de arranque está perfectamente definida en el script que nos sirve de plantilla (/etc/init.d/skeleton). Este script lo encontramos por defecto en cualquier sistema openSUSE.

Los scripts de arranque, como cualquier otro script de shell, empiezan todos con la línea

#!/bin/sh

o bien

#!/bin/bash

Luego normalmente vemos muchas líneas de comentarios. Estas hacen mención a información relativa al autor, el copyright o la licencia. El archivo debe incluir una cabecera especial con meta información acerca del script. Mira las convenciones acerca de los comentarios para saber más acerca de esto. Mira también la lista de estados definidos que están definidos en openSUSE.

El siguiente ejemplo está sacado del script /etc/init.d/esound:

 # Copyright (c) 1995-2002 SUSE Linux AG, Nuernberg, Germany.
 # All rights reserved.
 #
 # Author: Stanislav Brabec, feedback to http://www.suse.de/feedback
 #
 ### BEGIN INIT INFO
 # Provides:          esound
 # Required-Start:    alsasound
 # Should-Start:      $network portmap
 # Required-Stop:     alsasound
 # Should-Stop:      $network portmap
 # Default-Start:     5
 # Default-Stop:
 # Short-Description: Sound daemon with network support
 # Description:       Starts esound server to allow remote access to sound
 #       card. To use esound locally, you do not need to start this
 #       server on boot. You should edit server settings before
 #       starting it via sysconfig editor: Network/Sound/Esound
 ### END INIT INFO

A continuación también encontramos definidos los chequeos que comprueban que el demonio está correctamente instalado, y que se encuentran disponibles los ficheros de configuración necesarios. En caso de problemas, deben retornarse en cada caso los códigos de error definidos en la LSB. Para más detalles mira aquí los códigos de salida.

Este es un ejemplo sacado del script /etc/init.d/ypbind:

YPBIND_BIN=/usr/sbin/ypbind
 test -x $YPBIND_BIN || { echo "$YPBIND_BIN not installed";
         if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; }
 
 YPBIND_CONFIG=/etc/sysconfig/ypbind
 test -r $YPBIND_CONFIG || { echo "$YPBIND_CONFIG not existing";
         if [ "$1" = "stop" ]; then exit 0; else exit 6; fi; }
 
 # Read config
 . $YPBIND_CONFIG

Más adelante también se definen las funciones de estado y se implementa el cambio de estado (rc). Este ejemplo está sacado del script /etc/init.d/network:

. /etc/rc.status
rc_reset

Luego se implementan las acciones requeridas por el script. Echa un vistazo a /etc/init/d/skeleton, que viene con un código de ejemplo e incluye comentarios muy clarificadores. El siguiente ejemplo es un extracto del script /etc/init.d/cron:

case "$1" in
    start)
        echo -n "Starting CRON daemon"
        startproc $CRON_BIN
        rc_status -v
        ;;
    stop)
        echo -n "Shutting down CRON daemon"
        killproc -TERM $CRON_BIN
        rc_status -v
        ;;
    try-restart)
        $0 status >/dev/null &&  $0 restart
        rc_status
        ;;
    restart)
        $0 stop
        $0 start
        rc_status
        ;;
    force-reload)
        echo -n "Reload service Cron"
        checkproc $CRON_BIN
        rc_status -v
        ;;
    reload)
        rc_status -v
        ;;
    status)
        echo -n "Checking for Cron: "
        checkproc $CRON_BIN
        rc_status -v
        ;;
    probe)
        ;;
    *)
        echo "Usage: $0 {start|stop|status|try-restart|\
restart|force-reload|reload|probe}"
        exit 1
        ;;
esac

Finalmente, los scripts de arranque deben terminar devolviendo el código de salida correcto. Por esto, el último comando suele ser la función rc_exit.

Convenciones acerca de los comentarios

Los scripts de inicio son como cualquier otro script de consola, los comentarios en el código se delimitan con el símbolo '#' y pueden usarse sin limitaciones. Sólo hay una excepción; la LSB define un comentario especial de cabecera que proporciona cierta meta information acerca del script. Esta cabecera debe incluirse en todos los scripts de arranque y presenta la siguiente estructura:

### BEGIN INIT INFO
 # Provides:                   boot_facility_1 [ boot_facility_2 ...]
 # Required-Start:             boot_facility_1 [ boot_facility_2 ...]
 # Should-Start:               boot_facility_1 [ boot_facility_2 ...]
 # Required-Stop:              boot_facility_1 [ boot_facility_2 ...]
 # Should-Stop:                boot_facility_1 [ boot_facility_2 ...]
 # Default-Start:              run_level_1 [ run_level_2 ...]
 # Default-Stop:               run_level_1 [ run_level_2 ...]
 # Short-Description:          single_line_description
 # Description:                multiline_description
 ### END INIT INFO

Estas palabras clave que vemos aquí tienen el siguiente significado:

  • Provides define los nombres de los servicios que proporciona el script. Suele tratarse de el nombre de un demonio. Si más de un paquete pueden proporcionar el mismo servicio (por ejemplo, los paquetes sendmail y postfix, o también dhcpcd y dhclient), entonces los scripts de arranque de ambos paquetes deben proporcionar también nombres coincidentes.
  • Required-Start define qué demonios deben estar disponibles para poder iniciar y arrancar nuestro servicio. El sistema init es el responsable de asegurar que estos servicios estén arrancados de antemano.
  • Should-Start es un campo opcional. Su función es similar a Required-Start, pero no conlleva una dependencia estricta. Si un servicio listado aquí no está instalado, o no se arranca de forma automática, simplemente se ignora.
  • Required-Stop define los servicios que deben estar todavía disponibles durante el apagado de nuestro servicio. Nuevamente es tarea del sistema init el asegurarse de que se encuentren aún en ejecución para que nuestro script pueda detenerse de forma correcta.

Actualmente, openSUSE ignora esta cabecera, ya que el script de arranque de SUSE usa un esquema de enlace distinto (míralo en la página man init.d(7)).

  • Should-Stop es un campo opcional. Su función es similar a Required-Stop, pero no conlleva una dependencia estricta. Si un servicio de los que se listan no está instalado, o no se arranca de forma automática, simplemente se ignora.
  • Default-Start define en qué niveles de ejecución debería arrancarse nuestro script de forma automática. Los niveles de ejecución han cambiado desde SUSE Linux 7.1.
  • Default-Stop define los niveles de ejecución en los que nuestro script debería detenerse de forma automática.

Actualmente, openSUSE ignora esta cabecera, ya que el script de arranque de SUSE usa un esquema de enlace distinto (míralo en la página man init.d(7)).

  • Short-Description especifica una descripción sencilla de la función del servicio, en una sola línea. Esto se muestra, por ejemplo, en el Editor de niveles de ejecución de YaST.
  • Description es una descripción más detallada de la función de nuestro servicio. Cada línea adicional debe empezar con el símbolo '#', seguido por carácter de tabulado, o al menos dos espacios. Esta descripción multilínea acaba cuando se encuentra la primera línea que no coincide con este patrón. Esta información también se muestra en el Editor de niveles de ejecución de YaST.

La LSB permite definir en la cabecera extensiones específicas para cada distribución. Estas extensiones tienen el prefijo X-VendorTag-. En openSUSE están disponibles las siguientes:

  • X-SuSE-Should-Start tiene el mismo significado que Should-Start. Quedó obsoleta a partir de la LSB 2.0, en la que se incluyó Should-Start.
  • X-SuSE-Should-Stop tiene el mismo significado que Should-Stop. Quedó obsoleta desde que la LSB 2.0 incluyó Should-Stop.
  • X-UnitedLinux-Default-Enabled define si el servicio debería habilitarse por defecto. Los valores posibles son yes o no. Inicialmente, fue creada para usarse en United Linux pero puede usarse igualmente en SUSE.
  • X-UnitedLinux-Should-Start es lo mismo que X-SuSE-Should-Start pero para United Linux.
  • X-UnitedLinux-Should-Stop es lo mismo que X-SuSE-Should-Stop pero para United Linux.

Estados definidos por defecto

Tal como marca la LSB, openSUSE proporciona ya algunos nombres de estado por defecto. Se encuentran definidos en /etc/insserv.conf. Hasta el momento, están definidos:

  • $local_fs — Todos los sistemas de ficheros locales están montados. La mayoría de los servicios deberían necesitar esto.
  • $remote_fs — Todos los sistemas de ficheros remotos están montados. Como /usr puede ser montado remotamente, muchos servicios deberían necesitar también de esto.
  • $syslog — El registro del sistema está funcionando.
  • $network — La red está activa a bajo nivel (tarjeta de red, etc.).
  • $named — Está ya disponible la resolución de nombres de hosts.
  • $netdaemons — Todos los demonios de red funcionando. Esto fue quitado en la LSB 1.2. Por ahora se encuentra disponible por un tema de compatibilidad.
  • $time — La hora del sistema ha sido configurada correctamente.
  • $portmap — El mapeador de puertos SunRPC está disponible.

Acciones

Tal como marca la LSB, todos los scripts de arranque deben saber manejar los siguientes argumentos:

  • start — Arranca el servicio.
  • stop — Detiene el servicio.
  • restart — Detiene y arranca el servicio si ya estaba en funcionamiento. Si no lo estaba, simplemente lo arranca.
  • reload — Provoca la recarga de la configuración del servicio sin detenerlo o reiniciarlo.
  • force-reload — Provoca la recarga de la configuración del servicio si es que lo soporta. Si no, reinicia el servicio.
  • status — Muestra el estado actual del servicio.

Las acciones start, stop, restart, force-reload, y status deben estar definidas en todos los scripts de arranque. La acción reload es opcional.

SUSE define las siguientes acciones adicionales:

  • try-restart — Reinicia el servicio sólo si ya estaba activo antes. Esta acción forma parte ya de la LSB (desde la 1.9). Red Hat cuenta con una acción similar. llamada condrestart.
  • probe — Comprueba si es necesario recargar el servicio. Dependiendo del servicio, responde "reload" o "restart", si se requiere recargar el servicio. No muestra nada si no es necsario hacer nada. Esta acción es opcional y no forma parte de la LSB (desde la versión 1.9).

Códigos de salida

La LSB define los siguientes códigos de salida para los scripts de arranque:

Código de salida

Descripción

0

éxito

1

error genérico o no especificado

2

argumentos inválidos o demasiados argumentos

3

acción no implementada (por ejemplo, "reload")

4

el usuario no tiene privilegios suficientes

5

el programa no está instalado

6

el programa no está configurado

7

el programa no está arrancado

8-99

reservados para usos futuros de la LSB

100-149

reservados para uso de la distribución

150-199

reservados para uso de la aplicación

200-254

reservados

NOTA: Arrancar un servicio ya arrancado, detener o reiniciar un servicio que no se está ejecutando, así como reiniciar mediante force-reload (en el caso de que no esté soportada la señalización) se considera éxito.

Funciones de estado

Las funciones definidas en /etc/rc.status ayudan a grabar, mostrar y devolver información sobre el estado actual de los scripts de arranque. Pueden instanciarse desde los scripts de esta manera:

. /etc/rc.status

Están disponibles las siguientes funciones:

rc_active

Esta función comprueba si un servicio ha sido habilitado o no (mediante symlinks). Devuelve “0” si el servicio está habilitado en un nivel de ejecución, y devuelve “1” en caso contrario.

rc_exit

Esta función termina un script de arranque con un código de salida apropiado, de acuerdo al estado global de rc.

rc_failed [num]

Esta función fija los estados rc local y global con un valor determinado definido con el parámetro num. El “1” es el código por defecto.

rc_check

Comprueba el código de salida del último comando ($?) y fija el estado local de rc a este valor, si el valor es distinto de “0”. Luego fija el estado rc global a el valor del estado rc local si es distinto de “0”. Esta función se usa internamente por otras funciones de estado rc.

rc_reset

Fija los estados rc local t global a “0”.

rc_status [-r] [-s] [-u] [-v[num]]

Comprueba, fija y muestra el estado rc. Por defecto no hace nada; sólo llama a rc_check. Por tanto, debe llamrse con algún parámetro que muestre el estado. Los parámetros significan lo siguiente:

  • -r llama a rc_reset. Esta opción se puede usar junto a -v. El comando rc_status -v -r comprueba, fija y muestra el estado actual rc. Luego se llama a rc_reset.
  • -s muestra “skipped” y fija el estado a “3”. Significa característica no implementada.
  • -u muestra “unused” y fija el estado a “3”. Significa característica no implementada.
  • -v[num] muestra el estado actual y cambia el estado local a “0”. Por defecto, el estado se muestra en la línea actual. El parámetro num define que se deberían mostrar num líneas anteriores a la posición actual del cursor.

Instalación

openSUSE proporciona varias herramientas para administrar los scripts de arranque. La más sencilla es el comando insserv. Por ejemplo, para cargar el script de ejemplo /etc/init.d/miscript en los niveles de ejecución por defecto, ejecuta:

insserv /etc/init.d/miscript

Para desinstalarlo, escribe

insserv -r /etc/init.d/miscript

Otra herramienta es el Editor de niveles de ejecución de YaST. Puedes lanzarlo desde la línea de comandos mediante yast runlevel, o abriendo YaST desde el escritorio, bajo la opción Sistema. En el modo simple, habilitar un servicio lo añade a los niveles de ejecución por defecto. En modo experto, puedes especificarlos tú mismo.

Editor de niveles de ejecución de YaST

Información Adicional

Si quieres saber más, consulta las siguientes páginas man:

init(8), init.d(7), insserv(8)

O echa un vistazo a los siguientes artículos:

<keyword>init.d,init-script,init,initscript,insserv,script</keyword>