Friday, April 26, 2019

История современных систем инициализации.

Оригинал:
https://blog.darknedgy.net/technology/2015/09/05/0/

"данный момент" - это 09.2015

Под супервизором подразумевается служба, обеспечивающая контроль над стартом, остановкой и исполнением сервисов - например, он может перезапустить зависшую программу.

описание Sys V и BSD-style взято из статьи Ричарда Гуча: https://blog.darknedgy.net/technology/2015/09/05/0

Тема управления процессами и init в юникс-подобных системах в большой степени подвержена нарушениям хронологии и "попсовым" объяснениям. Это приводит к путанице и непониманию соответствующего функционала, и того, как формулируются задачи, связанные с надежным управлением процессами в Unix вообще, что делает этот предмет объектом для демагогов разного рода.

Когда речь заходит о GNU/Linux, наиболее распространено мнение, что хронологически первым был sysv init. Он был так себе, но по каким-то причинам с этим долго никто ничего не делал, пока Эппл не создали launchd, вдохновив Убунту на Upstart (или наоборот, в зависимости от того, кому вы симпатизируете), что только сделало его более тормозным. Затем в 2010 г. появилась systemd, и всё изменилось. А, да, тем временем Генту создала что-то под названием OpenRC или вроде того.

На самом деле, хронология событий плохо изучена, что часто влияет на представления о том, насколько новаторскими являются существующие решения. Важно то, что без понимания хронологии вы не можете учиться на ошибках прошлых версий и, возможно, в конце концов повторите их в своем творении.

Цель данной статьи - внести ясность в хронологию попыток создать "современные" системы инициализации. Под современными здесь подразумеваются все попытки улучшить классические BSD и System V стили инициализационных скриптов и управления процессами.

Статья не даёт технических решений, а просто перечисляет, что было сделано, чтобы люди, интересующиеся исследованием системного ПО и конкретно контролем процессов в Unix, могли использовать её как краткую справку. Не менее важно проинформировать случайных читателей в этой проблемной области, что, надеюсь, расширит их кругозор в отношении данного вопроса.

Я не стану углубляться в технические детали, а сделаю общие обзоры и дам ссылки на более подробную информацию.

Эта статья не касается основных супервизоров, которые не могут быть адаптированы к демонам init, таких как supervisord, monit, Circus, God, bluepill Eye. Они популярны у веб-разработчиков, потому что многие из них написаны на языках типа Питона и Руби, но они не являются системами инициализации, а также не являются оригинальными.

IBM System Resource Controller (1992)
Вероятно первая система init, написанная для AIX. В ней впервые настояли на общеизвестной семантике супервизора, когда не сервисы сами себя переводят в фоновое состояние, а этим занимается супервизор. Также в ней впервые действия производились не над отдельными демонами, а над "подсистемами", которые могли представлять из себя группы демонов и вспомогательных программ. Через 13 лет SMF в Solaris использовал этот же принцип.

SRC содержала в себе весь функционал управления сервисами: в ней были инструменты для их запуска, перезапуска, остановки и получения данных о состоянии подсистемы.

SRC не основывалась на скриптах или даже традиционных конфигах системных служб, а имела соственную ООБД, в которой регистрировались подсистемы и сервисы с помощью специальных команд. SMF также повторил эту идею в своем хранилище конфигурационных данных сервисов, где лежат данные выполнения и постоянные конфигурации, хотя также остались видимые пользователю файлы конфигурации в формате XML.

DAEMONTOOLS (1997) + DERIVATIVES (1997-2015)
Уравнения Максвелла в управлении процессами Юникс.

Изначально созданные Даниелом Бернштейном в 1997, с тех пор они обрели большое влияние и используются по сей день. На их основе было создано несколько деривативов, а также они повлияли на системы, несколько отклонявшиеся от их модели, такие как minit, ninit and depinit. По сути все системы инициализации можно представить как расширения daemontools в той или иной форме
(например systemd => nosh).

Вот страница самого Бернштейна: http://cr.yp.to/daemontools.html.

▪ rc.d (2000)
Это модульная конструкция скриптов инициализации, основанная на зависимостях, первоначально принятая в  NetBSD примерно в 2000 г., разработанная Люком Мьюборном. Затем она проникла в другие BSD, заменив старую плоскую /etc/rc.

В rc.d демон init исполняет /etc/rc, который запускает программу rcorder для определения порядка запуска скриптов в /etc/rc.d/, основываясь на их зависимости друг от друга. Скрипты инициализации написаны в ясном, стандартном формате, основанном на файле общих подпрограмм  /etc/rc.subr. В свою очередь, поведение всей системы и запуск служб - какие запускать и какие из них отключены, названия конфигов и других модулей - конфигурируется в файле /etc/rc.conf - это шелл-скрипт, порождаемый /etc/rc и работающий с парами ключ-значение.

rc.d обладает большой гибкостью и возможностями тонкой настройки, при этом основные недостатки систем на основе System V в ней искоренены. Oднако она реализует лишь базовое управление сервисами. До перехода на systemd в 2012 Арч Линукс имел  rc.d-подобную систему инициализации.

SIMPLEINIT, JINIT AND THE NEED(8) (2001-3)
Simpleinit описана в статье Ричарда Гуча 2002 года https://blog.darknedgy.net/technology/2015/09/05/0/ как нечто среднее между SysV и BSD-стилем с некоторыми особенностями.

Вкратце, она была основана на каталоге в /sbin/init.d, содержащем короткие скрипты, запускающие службы. Порядок запуска синхронизировался с помощью двух небольших утилит: need(8) and provide(8), являющихся символическими ссылками на argv[0] of initctl(8).

Эти две утилиты должны были избавить систему от необходимости в ранлевелах и обеспечить управление зависимостями. provide(8) регистрирует службу на основе имени, а need(8) запускает и останавливает сервисы путем блокировки, если имя сервиса зарегистрировано.Была также утилита display-services(8) для отображения статуса, либо использовался стандартный файл SysV inittab(5). См. также мануал initctl(8).

Эта система добилась некоторых скромных успехов; её включили в несколько проектов встроенных систем и экспериментальных проектов. Также она служит первым примером инициализации, основанной на зависимостях. На данный (09.2015) момент она используется как минимум в одном живом дистрибутиве - Source Mage GNU/Linux.

simpleinit вдохновила Джона Фремлина написать производную систему на С++, которая называлась  jinit и необычным образом использовала очередь сообщений System V для межпроцессного взаимодействия. С 2003 г. она не развивается.

* BSD-style
Загрузка контролируется одним скриптом или небольшим набором. Обычно существует главный скрипт загрузки (как правило это  /etc/rc), организующий весь процесс загрузки. Эта схема проста для понимания, так как скриптов мало, а порядок их запуска определяется главным скриптом. Это быстрая, простая и эффективная система.
Её недостаток - проблема масштабируемости. Если какой-то сторонний пакет создает инициализационный скрипт, запускающийся во время загрузки, то ему нужно редактировать один из существующих скриптов. Это опасно, так как скрипты загрузки, мягко говоря, хрупкие. Oшибка инсталлятора может привести к тому, что система не будет загружаться.

* SysV-style
Это надежная и масштабируемая система, но слишком сложная и тяжеловесная. В основном каталоге (обычно /etc/rc.d/init.d/) находится ряд мини-скриптов, которые все вместе могут загрузить большую часть системы. Каждый из скриптов запускает и останавливает одну службу.
Управляет процессом загрузки главный скрипт, который производит действия по настройке, которые было сложно поместить в мини-скрипт, а затем начинает исполнять каждый из мини-скриптов в другом каталоге. Порядок исполнения основан на правилах раскрытия подстановочных символов оболочки командной строки.
В этом другом каталоге находятся симлинки на скрипты из /etc/rc.d/init.d/ - по две ссылки на каждый скрипт: одна имеет название, начинающееся на S, другая - на K. S - это start, эти скрипты вызываются при загрузке системы. K - kill, скрипты вызываются при остановке. Порядок зависит от цифр после букв S и К: S10 будет запущен раньше, чем S15, который будет запущен раньше, чем S20. Изначально имена ссылкам дает системный интегратор. Cторонние установщики пакетов могут просто поместить свой скрипт запуска в /etc/rc.d/init.d/, а затем создать ссылку на него в "другом каталоге". Инсталлятор должен выбрать имя, которое ещё не используется, а также определить номер, который зависит от того, насколько далеко от начала загрузочного процесса должен запускаться скрипт.
Поэтому автор системных скриптов должен оставлять пробелы между номерами, чтобы можно было добавлять числа. Обычно используются числа 10, 20, 30, 40 и т.д. К числу можно добавить произвольную строку, что значительно увеличивает количество вариантов нумерации. Обычно к числу добавляется имя  скрипта: 10inetd. Таким образом можно группировать скрипты: порядок запуска между группами будет строго пределен, а внутри группы неизвестен или неважен.
Схема загрузки SysV также поддерживает концепцию ранлевелов - уровней исполнения. Это означает, что можно загрузить систему "полностью" (с сетью, многопользовательским режимом и графикой), а можно только частично - например, в однопользовательском режиме. Ранлевелы реализованы группировкой скриптов в "другом каталоге" в ряд каталогов, каждый из которых соответствует уровню исполнения. Обычно эти каталоги называются /etc/rc.d/rc0.d/ /etc/rc.d/rc1.d/ /etc/rc.d/rc2.d/ /etc/rc.d/rc3.d/ /etc/rc.d/rc4.d/ /etc/rc.d/rc5.d/ /etc/rc.d/rc6.d/.
Главный скрипт запускает все скрипты в каталоге ранлевела, который задан в inittab, с помощью telinit или параметром загрузки. Например, можно загрузиться в однопользовательский режим, запустив скрипты из /etc/rc.d/rc1.d/. Затем, после обслуживания системы, можно загрузиться полностью - в этом случает сервисы ранлевела 1 останавливаются, а затем запускаются скрипты из /etc/rc.d/rc5.d/. Аналогично происходит переход от более высокого ранлевела к более низкому - путем остановки сервисов.
Проблема SysV init  в том, что эта хренова туча каталогов с ссылками усложняет отслеживание статуса служб: какие из них запущены и что происходит в целом.

minit (2001-2)
Разработана Fefe (Феликс фон Ляйтнер). Её можно описать как инвертированный (эндогенный) daemontools.

Там, где  daemontools порождает отдельный процесс-супервизор для каждой службы,  minit объединяет их в центральный супервизор msvc. Также minit имеет очень простую систему зависимостей: в каждом каталоге для сервиса есть файл "depends", служащий для определения порядка запуска сервисов. Службы могут запускаться как синхронно, так и асинхронно.

minit имеет минимальный размер и должен линковаться с dietlibc, созданной тем же автором. Принципы системы описаны подробно здесь: http://www.fefe.de/minit/minit-linux-kongress2004.pdf

Никола Владов позже создал форк, названный ninit, расширив функционал minit большим количеством параметров конфигурирования и добавив совместимость с sysvinit.

▪DEPINIT (2002)
Написан Ричардом Лайтманом примерно в 2002. Он сам описал эту систему как "объединяющую идеи sysvinit, simpleinit, daemontools and make".

Она поддерживала параллельный запуск служб, относительно интеллектуальную (для своего времени) систему зависимостей, в которой вычислялось минимальное количество зависимых служб при остановке какой-либо из них; ротация логов происходила через конвейеры, а  сигналы для процессов настраивались пользователем. Вместо ранлевелов была группировка сервисов по имени в файловой системе, а процедура shutdown была полностью автономной и не зависела от скриптов.

Скрипты использовались, но были гораздо более краткими, благодаря наличию разумной системы управления процессами.  К сожалению, система не привлекла значительного внимания к себе и умерла.

DAEMOND (2002-3)
Малоизвестная, но интересная с исторической точки зрения daemond имела относительно замысловатую для того времени систему разрешения зависимостей, включавшую специальные строфы для модулей ядра. У неё также был собственный синтаксис конфигов, основанный на блоках, которые могли опционально включать в себя фрагменты скриптов оболочки (аналогично заданиям Upstart)
 Например:

 service "fsck" {
    description "Check filesystems";
    require "lvm";
    setup "/sbin/fsck -C -R -A -a";
}

service "mount-local" {
    require "fsck";
    description "Mount local filesystems";
    setup "/sbin/mount -a -v -t nonfs,nosmbfs";
}

Имелся также исходный файл конфигурации /etc/daemond.rc, разработанный для быстрого параллельного запуска.

Строфы зависимостей выглядели следующим образом:

require "file-or-service";
    This states that the service cannot be started at all unless the
    file is present, or the service has been succesfully started.

  need "file-or-service";
        Same as require, except that if the dependency cannot be satisfied
    then the entire service is made unavaliable, as though it did not
    exist (so that services that depend on it will be able to proceed).
    This is useful when you want a service that must start when some
    condition is met, but which is optionnal otherwise.

  want "service";
    This is not a proper dependency, but a 'collaborating' service.  This
    directive states that if the service where it appears starts, then
    service must be attempted as well, but need not succeed.

  require module "module";
  need module "module";
        Same as the first two, but for kernel modules.  It is usually better
    to rely on kernel autoloading for the most part.

  group "group";
    This places the service in a group.  That group can then be refered
    to as if it was a service (starting all of the group) and will be
    deemed successful if all the members of the group are started,
    unless...

  require any "group";
    ...is used, in which case the group will be deemed succesful if /any/
    service in the group is started.

Система была написана на С++, а не на С, и у автора явно были связанные с системой амбиции: он хотел, чтобы она стала главной альтернативой "допотопным" стилям SysV и BSD. Однако она не произвела впечатления.

▪ GNU dmd (2003)
dmd (daemon managing daemons) - система, впервые выпущенная Вольфгангом Йерлингом, примечательная тем, что была полностью написана на языке  Guile Scheme и на нём же конфигурировалась.

Примерно 10 лет пребывала в коматозном состоянии, а в 2013 г. была возрождена как часть универсального пакетного менеджера Guix, также написанного на Гайле. На сегодняшний день используется для управления службами и демонами в дистрибутиве Guix.

Она была хорошо документирована и в общем проста, основываясь на зависимостях в форме отношений provides/requires; шаблоны конфигурации сервисов были макросами на Scheme многоразового использования, включая так называемые конструкторы, включавшие различные варианты порядка запуска.

Благодаря использованию языка Scheme, она отличалась гибкостью и масштабируемостью. Вот пример из исходников GuixSD:

(define (root-file-system-service)
  "Return a service whose sole purpose is to re-mount read-only the root file
system upon shutdown (aka. cleanly \"umounting\" root.)

This service must be the root of the service dependency graph so that its
'stop' action is invoked when dmd is the only process left."
  (with-monad %store-monad
    (return
     (service
      (documentation "Take care of the root file system.")
      (provision '(root-file-system))
      (start #~(const #t))
      (stop #~(lambda _
                ;; Return #f if successfully stopped.
                (sync)

                (call-with-blocked-asyncs
                 (lambda ()
                   (let ((null (%make-void-port "w")))
                     ;; Close 'dmd.log'.
                     (display "closing log\n")
                     ;; XXX: Ideally we'd use 'stop-logging', but that one
                     ;; doesn't actually close the port as of dmd 0.1.
                     (close-port (@@ (dmd comm) log-output-port))
                     (set! (@@ (dmd comm) log-output-port) null)

                     ;; Redirect the default output ports..
                     (set-current-output-port null)
                     (set-current-error-port null)

                     ;; Close /dev/console.
                     (for-each close-fdes '(0 1 2))

                     ;; At this point, there are no open files left, so the
                     ;; root file system can be re-mounted read-only.
                     (mount #f "/" #f
                            (logior MS_REMOUNT MS_RDONLY)
                            #:update-mtab? #f)

                     #f)))))
      (respawn? #f)))))


▪ PINIT (2003)
Это была малоизвестная, но на удивление значимая система инициализации, разработанная Воутером фон Клауненом где-то в 2003.
Возможно, это была первая система, где сервисы конфигурировались на XML, опередившая даже launchd и SMF. Это выглядело примерно так:

<?xml version="1.0"?>
<command provides="system.swap">
    <startup message="Activating all swap partitions...">
        /sbin/swapon -a
    </startup>
    <shutdown message="Deactivating all swap partitions...">
        /sbin/swapoff -a
    </shutdown>
    <dependency name="system.checkfs"/>
</command>

Как видно, она имела систему контроля зависимостей (основанную скорее на порядке выполнения, а не службу,  полностью отслеживающую транзакции, как в SMF или systemd). Она поддерживала параллельный запуск сервисов, а также, возможно, первая имела систему плагинов. То есть различные процедуры загрузки не прописывались в демоне init или скриптах, а подгружались и выгружались из адресного пространства pinit как динамические библиотеки, хотя формально API не существовало. От ранлевелов отказались в пользу статических профилей, содержавших список служб, которые надо было запусить/остановить для перехода в другое состояние, что напоминает настройки systemd.

По сравнению с предшественниками система была несколько тяжеловесной, используя библиотеки libxml и GLib. В конце концов её забросили, и она не произвела впечатления.

▪ initng (2005)
Выпущенная Джимми Веннландом в марте 2005, система тестировалась в основном на Генту и была одной из самых амбициозных и завершенных систем новой школы. Помимо обычного управления процессами, группировки сервисов (группы назывались уровнями исполнения), контроля зависимостей и параллельного запуска служб, она прославилась своей обширной системой плагинов, которые могли эффективно взаимодействовать с более чем 20-ю подсистемами, закрытыми для initng. Демон init был преобразован в специальный загрузчик и обработчик модулей. Сами сервисы конфигурировались в формате блоков, называемых ifiles. initng предоставлял множество готовых файлов, например:

service service/aumix {
    use = service/alsasound;
    need = system/initial system/bootmisc;
    stdall = /dev/null;
    script start = {
        if [ -f /etc/aumixrc ]
        then
            @/usr/bin/aumix@ -f /etc/aumixrc -L
        else
            @/usr/bin/aumix@ -v75 -c75 -w75
        fi
    };
    exec stop = @/usr/bin/aumix@ -f /etc/aumixrc -S;
}

По сути это можно рассматривать как всеобъемлющий метаинит.

В какой-то момент на него смотрели разрабы Убунту, но в итоге решили создать Upstart. После этого initng тихо умер, почти ничего не достигнув.

launchd (2005)
Возможно, первая система "новой школы", характерной чертой которой был перенос основной логики в демон init и общение с ним с помощью управляющей утилиты. Конфигурировалась в формате XML, в OS X также был демон начальной загрузки (реестр обнаружения) для служб ядра. Продвигал s6 для активизации сокетов. Разделяет системных демонов и агентов - сервисы пользователя; последние группируются в типы, объединенные в специфичные для OS X подсистемы, такие как loginwindow или Aqua UI. Использует чистую загрузку сервисов, формально не имея системы контроля зависимостей, так как предполагается, что сервисы будут синхронизироваться друг с другом через  IPC в стеке  OS X. Связывает типы процессов с политиками планировщика и ограничениями ресурсов, очевидно, для сохранения отзывчивости рабочего стола.

Рассматривалось применение системы в Убунту, но было отклонено из-за лицензии Apple Public Source License, несовместимой с GPL, которая использовалась на тот момент. В данный момент исследуется в рамках NextBSD и предполагается для дальнейшего использования во  FreeBSD.

▪ Service Management Facility (SMF) (2005)
Solaris SMF - вероятно первая система со сложным отслеживанием транзакций, которое производилось во внутреннем графическом движке. Предусматривает сложные сценарии управления сервером. Глубоко интегрирована с Solaris Fault Manager для отслеживания сбоев аппаратного обеспечения. Каждый сервис идентифицируется через FMRI (Fault Management Resource Identifier). Конфиги служб в формате XML затем объединяются в базу данных, называемую репозиторием конфигурации сервисов (в ней сервисы также могут хранить данные времени выполнения). Чтение из базы происходит с помощью svcprop, а её динамическая конфигурация - с помощью svccfg. Сами экземпляры служб контролируются с помощью svcadm, информация о статусе служб извлекается с помощью svcs.

SMF имеет главную службу контроля сервисов - svc.startd, управляющий зависимостями по умолчанию, - а также делегированные службы для каждого приложения. В Солярисе делегированной службой является  inetd. Подробней - на сайте документации Oracle:
https://docs.oracle.com/cd/E23824_01/html/821-1451/hbrunlevels-25516.html.

▪ eINIT (2006)
Аналогично initng, система основывалась на плагинах, сам init был только обработчиком. Также разрабатывалась для Генту. Конфигурировалась на XML. Имел значительно более высокую мета-конфигурируемость, чем  initng. Каждый модуль настраивался с помощью XML в манифесте einit.xml. Основан на типах зависимостей provides/requires и подсистеме событий, но больше для внутренних событий типа мониторинга загрузки/выгрузки модулей, а не для регистрации сервисов.

Пример:

<einit prefix="services-virtual-module">
 <daemon id="daemon-boinc"
  name="BOINC client"
  provides="boinc"
  requires="mount-critical"
  command="cd /var/lib/boinc; boinc_client"
  restart="yes" />
</einit>

Не смог набрать обороты и был заброшен.

Upstart (2006)
Создан Скоттом Джеймсом Ремнантом для Убунту. В свое время недолго использовался в Федоре, на данный момент - в ChromeOS. Убунту переехала на systemd.

Upstart основана на идее, что действия (например, старт и остановка сервисов) должны происходить в ответ на генерируемые системой или пользовательскими программами события. Она имеет несколько модулей, называемых мостами, для трансляции событий ядра и пространства пользователся в собственную очередь Upstart. Список встроенных событий определён в  upstart-events(7).

В Upstart впервые в качестве механизма коммуникации внутри  PID 1  использован D-Bus.

Таким образом, событие - это абстрактное пред- или постусловие для совершения действия в отношении сервиса. Они важны как для синхронизации, так и для динамизма и "ленивой загрузки".

http://upstart.ubuntu.com/cookbook/ - пособие по апстарт.


Asus eeePC fastinit + его производные (2007-2015)
Как часть линейки ноутбуков Asus’s eeePC около 2007-2008, которая имела варианты с предустановленной системой Xandros, они написали проприетарную замену init под названием  fastinit, специально созданную для...быстрой загрузки, я полагаю

В 2008 Клодио Мацуока провел обратную разработку фастинита Причина его быстроты была проста. Это была полностью автономная логика загрузки в виде маленькой программы на С, которая делала вызовы POSIX напрямую для всех операций, которые обычно запускаются как скрипты. Конфигурация производилась статически во время компиляции с помощью редактирования заданного макроса на С, который также не отличался гибкостью.

Однако в 2014-2015 появилось её ответвление  finit, значительно дополненное разработчиком встроенных систем Хоакимом Нильсоном: https://github.com/troglobit/finit.

Во многом похоже на упомянутый  pinit, finit работает с системой плагинов, динамически включающихся в логику загрузки, но у finit есть API. Она совместима с уровнями исполнения SysV и имеет встроенный  inetd для предварительного открытия серверных сокетов. Конфиг - простой файл /etc/finit.conf, вроде этого:

user admin
host testbed

check /dev/vda1

module button
module evdev
module loop
module psmouse

runlevel 2

network service networking start

tty /dev/tty1
tty /dev/tty2
tty /dev/tty3

# Alternative method instead of runparts
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start          -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd start            -- Preparing console
#run [2] /etc/init.d/networking start      -- Start networking

# Services to be monitored and respawned as needed
service [2345] /sbin/klogd -n             -- Kernel logging server
service [2345] /sbin/syslogd -n           -- Syslog server
service [3] /usr/sbin/gdm                 -- GNOME Display Manager

# Run start scripts from this directory
# runparts /etc/start.d

# Inetd services
inetd time/udp                wait [2345] internal          -- UNIX rdate service
inetd time/tcp              nowait [2345] internal          -- UNIX rdate service
inetd ssh@eth0:222/tcp      nowait [2345] /usr/sbin/sshd -i -- SSH service
inetd ssh/tcp               nowait [2345] /usr/sbin/sshd -i -- SSH service

# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
service :1 [2345] /sbin/httpd -f -h /http -p 80   -- Web server
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server

finit ориентирована на маленькие и встроенные системы, но при этом очень гибкая.

OpenRC (2007)
Используется прежде всего в Генту, но также в Alpine Linux и др. Предназначена для замены ранних скриптов базовой схемы Генту. На самом деле в OpenRC нет демона init, но есть всеобъемлющая структура управления процессами (хотя и недостаточная в смысле супервизора, так как предполагается её интеграция с внешними супервизорами, такими, как s6 daemontools-подобный супервизор), созданная под сильным влиянием rc.d из систем  BSD, отсюда и её название. Обзор можно найти в Генту-вики.

▪ Android init (2008)
Это специализированный демон инит, созданный для работы с данной платформой и обеспечивающий обычную систему ленивой загрузки, основанную на событийно-ориентированном механизма, называемом actions. Некоторые из них определяются пользователем, другие - самим демоном. Файл конфигурации - /init.rc.

Детальный обзор системы - в этой статье: https://blog.darknedgy.net/technology/2015/08/05/0-androidinit/. Система не отличается оригинальностью. Её назначение - сделать так, чтобы вендоры могли один раз настроить её в initramfs и забыть.

 systemd (2010)
Изначально планировалось название Babykit. Интервью с поттерингом: www.linuxvoice.com/interview-lennart-poettering/.
(Видать автор тоже не большой любитель systemd :D. Хотя начиналось всё неплохо, но поттеринг забыл предупредить, что собрался заменить своим поделием ядро).

procd (2012)
Демон init маленького размера с функцией супервизора, разработанный специально для OpenWrt и используемый, соответственно, на роутерах. Он использует небольшую объектно-ориентированную реализацию шины сообщений, названную ubus, и поддерживает песочницу для сервисов в пространствах имен  и через фильтрацию системных вызовов, например, seccomp-bpf.

Для скриптов инициализации используется специальная библиотека:

START=50
USE_PROCD=1

start_service() {
   procd_open_instance
   procd_set_param command /usr/bin/xupnpd
   procd_append_param command -d /usr/share/xupnpd

   procd_set_param respawn
   procd_close_instance
}
Where the procd_ routines serialize the arguments into JSON and pass them over ubus.

Epoch (2014)
Epoch - это намеренно минималистичный демон init, осуществляющий полное управление процессами во время запуска, остановки и работы системы, но выполняющий все процессы последовательно/синхронно. Для сервисов использует метафору Object и так же, как Android init, настраивается в основном файле. Пример:


Hostname=FILE /etc/hostname
DefaultRunlevel=boot
EnableLogging=true
DisableCAD=true
BlankLogOnBoot=true
MountVirtual=procfs sysfs devpts+ devshm+

ObjectID=sysclock
    ObjectDescription=Configuring system clock
    ObjectStartCommand=hwclock -s
    ObjectStopCommand=hwclock -w
    ObjectStartPriority=1
    ObjectStopPriority=2
    ObjectEnabled=true
    ObjectOptions=RAWDESCRIPTION
    ObjectRunlevels=boot core

ObjectID=mountruntmp
    ObjectDescription=Mounting /run and /tmp
    ObjectStartCommand=/etc/epoch/scripts/mountruntmp.sh
    ObjectStopCommand=NONE
    ObjectStartPriority=2
    ObjectStopPriority=0
    ObjectEnabled=true
    ObjectOptions=RAWDESCRIPTION
    ObjectRunlevels=boot core hurr

ObjectID=rwfs
    ObjectDescription=root filesystem read-write support
    ObjectStartCommand=/bin/mount -o remount,rw /
    ObjectStopCommand=/bin/mount -o remount,ro /
    ObjectStartPriority=4
    ObjectStopPriority=6
    ObjectEnabled=true

Использует  свою собственную реализацию шины сообщений, основанную на разделяемой памяти System V. Как видно из примера, оперирует концепцией приоритетов при задании порядка, а не зависимостей. На основе приоритетов также можно создавать логические группы.


sinit (2014)
Über alles.

# MIT license.

#include <sys/types.h>
#include <sys/wait.h>

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define LEN(x) (sizeof (x) / sizeof *(x))

static void sigpoweroff(void);
static void sigreap(void);
static void sigreboot(void);
static void spawn(char *const []);

static struct {
    int sig;
    void (*handler)(void);
} sigmap[] = {
    { SIGUSR1, sigpoweroff },
    { SIGCHLD, sigreap     },
    { SIGINT,  sigreboot   },
};

static char *const rcinitcmd[]     = { "/bin/rc.init", NULL };
static char *const rcrebootcmd[]   = { "/bin/rc.shutdown", "reboot", NULL };
static char *const rcpoweroffcmd[] = { "/bin/rc.shutdown", "poweroff", NULL };

static sigset_t set;

int
main(void)
{
    int sig;
    size_t i;

    if (getpid() != 1)
        return 1;
    chdir("/");
    sigfillset(&set);
    sigprocmask(SIG_BLOCK, &set, NULL);
    spawn(rcinitcmd);
    while (1) {
        sigwait(&set, &sig);
        for (i = 0; i < LEN(sigmap); i++) {
            if (sigmap[i].sig == sig) {
                sigmap[i].handler();
                break;
            }
        }
    }
    /* not reachable */
    return 0;
}

static void
sigpoweroff(void)
{
    spawn(rcpoweroffcmd);
}

static void
sigreap(void)
{
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ;
}

static void
sigreboot(void)
{
    spawn(rcrebootcmd);
}

static void
spawn(char *const argv[])
{
    pid_t pid;

    pid = fork();
    if (pid < 0) {
        perror("fork");
    } else if (pid == 0) {
        sigprocmask(SIG_UNBLOCK, &set, NULL);
        setsid();
        execvp(argv[0], argv);
        perror("execvp");
        _exit(1);
    }
}


























2 comments: