Sistema 5 init
le contará solo una pequeña parte de la historia.
Hay una especie de miopía que afecta al mundo Linux. La gente piensa que usa algo llamado "Sistema 5 init
", y eso es tanto lo tradicional como el mejor lugar para comenzar. De hecho, tampoco es el caso.
La tradición no es de hecho lo que esa gente dice que es, para empezar. Sistema 5 init
y Sistema 5 rc
fecha a AT&T UNIX System 5, que fue casi tan lejano después del primer UNIX como lo estamos ahora (digamos) después de la primera versión de Linux-Mandrake.
1st Edition UNIX solo tenía init
. No tenía rc
. El lenguaje ensamblador de la primera edición init
(cuyo código ha sido restaurado y puesto a disposición por Warren Toomey et al.) generó y regeneró directamente 12 getty
procesos, montó 3 sistemas de archivos cableados desde una tabla integrada y ejecutó directamente un programa desde el directorio de inicio de un usuario llamado mel
. El getty
la tabla también estaba directamente en la imagen del programa.
Fue otra década después de UNIX System 5 que apareció el llamado sistema de inicio de Linux "tradicional". En 1992, Miquel van Smoorenburg (re-)escribió un init
de Linux +rc
y sus herramientas asociadas, a las que la gente ahora se refiere como "Sistema 5 init
", aunque en realidad no es el software de UNIX System 5 (y no es solo init
).
Sistema 5 init
/rc
no es el mejor lugar para comenzar, e incluso si uno agrega conocimiento de systemd, eso no cubre la mitad de lo que hay que saber. Ha habido mucho trabajo en el área del diseño del sistema de inicio (para Linux y BSD) que se ha llevado a cabo solo en las últimas dos décadas. Se han discutido, tomado, diseñado, implementado y practicado todo tipo de decisiones de ingeniería. Los Unices comerciales también hicieron mucho.
Sistemas existentes para estudiar y aprender
Aquí hay una lista incompleta de algunos de los principales sistemas de inicio aparte de esos dos, y uno o dos de sus (varios) puntos sobresalientes:
- El finit de Joachim Nilsson optó por usar un archivo de configuración más legible por humanos.
- El minit de Felix von Leitner optó por un sistema de configuración del sistema de archivos como base de datos, pequeñas huellas de memoria y dependencias de inicio/detención entre las cosas que
init
comienza. - El runit de Gerrit Pape se centró en lo que describí anteriormente como los cuatro scripts de shell que acaban de generar enfoque.
- InitNG tenía como objetivo tener dependencias, objetivos con nombre, múltiples archivos de configuración y una sintaxis de configuración más flexible con una gran cantidad de configuraciones para los procesos secundarios.
- advenedizo optó por un rediseño completo, modelando el sistema no como servicios e interdependencias en absoluto, sino como eventos y trabajos desencadenados por ellos.
- El diseño de nosh incluye la eliminación de toda la administración de servicios (incluso el
getty
desove y cosecha de zombis) en un administrador de servicios separado, y simplemente manejo de dispositivos/enlaces simbólicos/directorios y eventos del sistema "API" específicos del sistema operativo. - sinit es un inicio muy simple. Ejecuta
/bin/rc.init
cuyo trabajo es iniciar programas, montar el sistema de archivos, etc. Para esto, puede usar algo como minirc.
Además, hace unos 10 años, hubo una discusión entre los usuarios de daemontools y otros sobre el uso de svscan
como proceso #1, lo que llevó a proyectos como svscan de Paul Jarc como estudio de proceso 1, las ideas de Gerrit Pape y svscan de Laurent Bercot como proceso 1.
Lo que nos lleva a lo que hacen los programas del proceso #1.
Qué hacen los programas del proceso #1
Las nociones de lo que se "supone" que debe hacer el proceso n.° 1 son, por naturaleza, subjetivas. Un objetivo significativo criterio de diseño es lo que el proceso #1 como mínimo debe hacer. El kernel le impone varios requisitos. Y siempre hay cosas específicas del sistema operativo de varios tipos que tiene que hacer. Cuando se trata de qué proceso #1 tiene tradicionalmente hecho, entonces no estamos en ese mínimo y nunca lo hemos estado.
Hay varias cosas que varios kernels de sistemas operativos y otros programas exigen del proceso #1 de las que uno simplemente no puede escapar.
La gente te dirá que fork()
procesar cosas y actuar como padre de procesos huérfanos es la función principal del proceso #1. Irónicamente, esto no es cierto. Tratar con procesos huérfanos es (con kernels Linux recientes, como se explica en https://unix.stackexchange.com/a/177361/5132) una parte del sistema que uno puede en gran medida eliminar del proceso n.º 1 en otros procesos, como un administrador de servicios dedicado . Todos estos son administradores de servicios, que se quedan sin el proceso #1:
- IBM AIX
srcmstr
programa, el controlador de recursos del sistema - El
runsvdir
de Gerrit Pape de runit - Daniel J. Bernstein
svscan
de daemontools,svscan
de Adam Sampson de freedt,svscan
de Bruce Guenter de daemontools-encore, ys6-svscan
de Laurent Bercot de s6 - El
perpd
de Wayne Marshall del perpetrador - la función de administración de servicios en Solaris 10
- el
service-manager
de nosh
Del mismo modo, como se explica en https://superuser.com/a/888936/38062, todo el /dev/initctl
la idea no necesita estar cerca del proceso #1. Irónicamente, es el systemd altamente centralizado el que demuestra que se puede sacar del proceso n.º 1.
Por el contrario, las cosas obligatorias para init
, que la gente suele olvidar en sus diseños extravagantes, son cosas como el manejo de SIGINT
, SIGPWR
, SIGWINCH
, etc. enviados desde el kernel y promulgando las diversas solicitudes de cambio de estado del sistema enviadas desde programas que "saben" que ciertas señales para el proceso #1 significan ciertas cosas. (Por ejemplo:como se explica en https://unix.stackexchange.com/a/196471/5132, los conjuntos de herramientas BSD "saben" que SIGUSR1
tiene un significado específico.)
También hay tareas únicas de inicialización y finalización de las que uno no puede escapar, o sufrirá mucho si no las realiza, como montar sistemas de archivos "API" o vaciar el caché del sistema de archivos.
Los conceptos básicos para tratar con sistemas de archivos "API" son un poco diferentes a la operación de init
rom 1st Edition UNIX:Uno tiene una lista de información integrada en el programa y el otro simplemente mount()
s todas las entradas de la lista. Encontrará este mecanismo en sistemas tan diversos como BSD (¡sic!) init
, a través del nosh system-manager
, a systemd.
"configurar el sistema para un shell simple"
Como has observado, init=/bin/sh
no se montan los sistemas de archivos "API", se bloquea de manera desgarbada sin vaciar la memoria caché cuando se escribe exit
(https://unix.stackexchange.com/a/195978/5132) y, en general, deja que el (super)usuario realice manualmente las acciones que hacen que el sistema sea mínimamente utilizable.
Para ver lo que uno realmente no tiene más remedio que hacer en los programas de proceso n.º 1 y, por lo tanto, establecer un buen rumbo para su objetivo de diseño declarado, su mejor opción es observar las superposiciones en el funcionamiento del runit de Gerrit Pape, Felix von minit de Leitner y el system-manager
programa del paquete nosh. Los dos primeros muestran dos intentos de ser minimalistas, pero aún manejan las cosas que es imposible evitar.
Este último es útil, sugiero, por su extensa entrada manual para el system-manager
programa, que detalla exactamente qué sistemas de archivos "API" están montados, qué tareas de inicialización se ejecutan y qué señales se manejan; en un sistema que por diseño hace que el administrador del sistema genere otras tres cosas (el administrador de servicios, un registrador adjunto y el programa para ejecutar los cambios de estado) y solo haga lo inevitable en el proceso n.° 1.
System V init en Debian (hay otras variantes y variaciones) hace lo siguiente:
- Al ingresar a un nivel de ejecución, llama scripts en
/etc/rcX.d/S*
en orden alfanumérico, dondeX
es el nivel de ejecución. Estos scripts deberían configurar el nivel de ejecución. La configuración típica inicia demonios y realiza tareas de configuración para ese nivel de ejecución. Esto es algo que se hace una sola vez al ingresar al nivel de ejecución. - Mientras está en un nivel de ejecución, inicia los demonios que se enumeran en el
/etc/inittab
como la necesidad de estar activo durante ese nivel de ejecución. Si esos demonios dejan de ejecutarse, los reinicia. Si bien puede tener cualquier demonio que desee administrado porinit
, como mínimo quieres unos pocosgetty
para que pueda iniciar sesión.getty
sale una vez que se completa el inicio de sesión, luegoinit
lo reinicia, proporcionando un aviso de inicio de sesión nuevo.
- Si el daemon se reinicia demasiadas veces en muy poco tiempo, deja de intentar reiniciarlo por un tiempo.
- El hecho de que algo haya sido iniciado por los scripts de kickoff al ingresar al nivel de ejecución no hace
init
tratará automáticamente de mantenerlo funcionando. Debe especificarlo por separado en el/etc/inittab
.
- Al salir de un nivel de ejecución, llama a los scripts en
/etc/rcX.d/K*
en orden alfanumérico, dondeX
es el nivel de ejecución. Una forma de implementar el apagado o reinicio es definir un nivel de ejecución para esos eventos y hacer que la última tarea ejecutada seahalt
oreboot
comando. - Llamará ejecutables en respuesta a ciertos eventos, como eventos de encendido o Ctrl-Alt-Del.
- Escucha en un socket, si recibe ciertos mensajes cambiará el nivel de ejecución.
Entonces puedes usar init
como gerente de servicio rudimentario si lo desea, pero su tarea principal en estos días es mantener getty
está disponible para que un usuario pueda iniciar sesión e iniciar transiciones de nivel de ejecución.
Me preguntaba, ¿qué tareas hace init para configurar el sistema para un shell simple?
Lo que quieras. En Debian, en cada /etc/rcX.d
directorio es un enlace simbólico a un script en /etc/init.d
y puede personalizar completamente o eliminar esos scripts. El orden se establece anteponiendo cada script con un 00
, 01
, etc.
También puede especificar un -b
opción a init
(es decir, a través de la línea de comandos del kernel) si solo desea init
para generar un caparazón. Cuando salga del shell, init
muere y cuando init
muere, el núcleo entrará en pánico.
Lo mínimo absoluto que debe hacer init es ejecutar al menos otro programa y nunca salir. Si init sale, el sistema falla. Supongo que incluso ejecutar el otro programa no es estrictamente necesario, pero si no lo hace, init tendría que ser responsable de hacer todo lo que se espera que haga el sistema, o no sería muy útil.