Init process on UNIX and Linux systems
Init is the parent of all processes, executed by the kernel during the booting of a system. Its principle role is to create processes from a script stored in the file /etc/inittab. It usually has entries which cause init to spawn gettys on each line that users can log in. It controls autonomous processes required by any particular system.
After reading this file, how the system should be set up in each runlevel is determined by init and also set default runlevel. Init starts all background process after setting default runlevel for the system.
Runlevels
Runlevel, a software configuration of the system which allows only a selected group of processes to exist. The processes produced by init for each of these runlevels are defined in the /etc/inittab file.
Init can be in one of these eight runlevels: 0-6 and S or s. The runlevel can be changed by having a privileged user run telinit, which sends appropriate signals to init, telling it which runlevel to change to.
S or s are same.
7-9 are valid runlevels. though not really documented as «traditional» Unix variants don’t use them. runlevels S and s are in fact the same. Internally they are aliases for the same runlevel.
Runlevels | Functions |
---|---|
0 | To halt the system |
1 | To get the system down into single user mode |
2 | To get multiuser mode without networking |
3 | To get multiuser mode with networking |
4 | Not used |
5 | To get multiuser mode with networking and X windows |
6 | To reboot the system |
S or s | Not used directly. |
Booting
After invoking init as the last step of the kernel boot sequence, it sees if an entry of the type initdefault is present in the file /etc/inittab. The initdefault entry determines the initial runlevel of the system. If no such entry (or no /etc/inittab at all) is present there, a runlevel must be entered at the system console.
Changing Runlevels
After specifying all the processes, init waits for one of its descendant processes to die, a powerfail signal, or until it is signaled by telinit to change the system’s runlevel. It re-examines the /etc/inittab file, when one of the above three conditions occurs.
init still waits for one of the above three conditions to occur. For providing an instantaneous response, the telinit Q or q command can wake up init to re-examine the/etc/inittab file.
If init is not in single user mode and receives a powerfail signal (SIGPWR), it reads the file /etc/powerstatus. Then it starts a command based on the contents of this file −
Tag | Description |
---|---|
F(AIL) | Power is failing, UPS is providing the power. Execute the powerwait and powerfail entries. |
O(K) | Power has been restored, execute the powerokwait entries. |
L(OW) | The power is failing and the UPS has a low battery. Execute the powerfailnow entries. |
If /etc/powerstatus contains anything else then the letters F, O or L or doesn’t exist, init will behave as if it has read the letter F.
Usage of SIGPWR and /etc/powerstatus is discouraged. If Someone wanting to interact with init should use the /dev/initctl control channel — see the source code of the sysvinit package for more documentation about this.
When init is requested to change the runlevel, it sends the warning signal SIGTERM to all processes that are undefined in the new runlevel. Then It waits 5 seconds before forcibly terminating these processes via the SIGKILL signal.
Init assumes that all these processes and their descendants remain in the same process group which init originally created for them. It will not receive these signals, if any process changes its process group affiliation. Such processes need to be terminated separately.
TELINIT
/sbin/telinit is linked to /sbin/init which takes a one-character argument and signals init to perform the appropriate action. The following arguments serve as directives to telinit −
Tag | Description |
---|---|
0,1,2,3,4,5 or 6 | tell init to switch to the specified run level. |
a, b, c | tell init to process only those /etc/inittab file entries having runlevel a, b or c. |
Q or q | tell init to re-examine the /etc/inittab file. |
S or s | tell init to switch to single user mode. |
U or u | tell init to re-execute itself (preserving the state). No re-examining of/etc/inittab file happens. Request would be silently ignored, if Run level is not one of Ss12345. |
It can also tell init how long it should wait between sending processes the SIGTERM and SIGKILL signals. 5 seconds is the default, but this can be changed with the -t sec option.
Only by users with appropriate privileges can invoke telinit.
By looking at its process id, init binary checks if it is init or telinit; the real init’s process id is always 1. So, instead of calling telinit one can also just use init instead as a shortcut.
Источник
Исследуем процесс загрузки Linux
(C) В.А.Костромин, 2007
(версия файла от 03.10.2007 г.)
Этап 5: Процесс init и файл /etc/inittab
Как было показано в предыдущем разделе, если в параметре начальной загрузки «init=» не задан запуск какой-то другой программы, после монтирования корневой файловой системы в режиме «только для чтения» ядро запускает процесс init , который, как известно, является родоначальником всех других процессов в Linux. Сам по себе init в принципе ничем не отличается от других программ в системе Linux, просто это первая (и единственная) программа, которая запускается непосредственно ядром, все остальные процессы являются потомками процесса init. Файл программы init вы можете найти в каталоге /sbin среди других исполняемых файлов.
Init отвечает за продолжение процедуры загрузки, и перевод системы от начального состояния, возникающего после загрузки ядра, в стандартное состояние обработки запросов многих пользователей. Основная задача, которая стоит перед init, заключается в том, чтобы запускать в определенной последовательности другие программы в процессе загрузки системы и останавливать процессы в случае переключения уровня выполнения (в частности, при остановке системы). Init выполняет еще массу различных операций, необходимых для дальнейшей работы системы: проверку и монтирование файловых систем, запуск различных служб (демонов), запуск процедур логирования, оболочек пользователей на различных терминалах и т.д. Но, прежде чем рассматривать работу процесса init более детально, нужно сказать несколько слов о стилях загрузки и так называемых «уровнях выполнения».
5.1. Уровни выполнения
Уровни выполнения (run levels) – это просто несколько стандартных вариантов загрузки системы, каждый из которых определяет перечень действий, выполняемых процессом init , и состояние системы после загрузки, т. е. конфигурацию запущенных процессов. Уровень выполнения идентифицируется одним символом. В большинстве дистрибутивов ОС Linux используется 6 основных уровней выполнения. В следующей таблице показано, как эти уровни используются в дистрибутивах Slackware и Red Hat:
Уровень | Slackware | Red Hat |
---|---|---|
0 | остановка системы | остановка системы |
1 | однопользовательский режим | однопользовательский режим |
2 | использование не регламентировано | многопользовательский режим без NFS (то же, что и 3, если компьютер не работает с сетью) |
3 | многопользовательский режим | полный многопользовательский режим |
4 | запуск системы в графическом режиме (X11 с KDM/GDM/XDM) | использование не регламентировано |
5 | использование не регламентировано | запуск системы в графическом режиме |
6 | перезагрузка системы | перезагрузка системы; |
В некоторых дистрибутивах (например, в Debian), кроме того, используется дополнительный уровень S (или s) — примерно то же, что и однопользовательский режим, но S и s используются в основном в скриптах.
Как видите, уровни 0, 1 и 6 зарезервированы для особых случаев. Относительно того, как использовать уровни со 2 по 5, единого мнения не существует. Некоторые системные администраторы используют разные уровни для того, чтобы задать разные варианты работы, например, на одном уровне запускается графический режим, на другом работают в сети и т. д. Вы можете сами решить, как использовать разные уровни для создания разных вариантов загрузки. Но для начала проще всего воспользоваться тем способом определения разных уровней, который был задан при установке.
Уровень выполнения может быть задан как одна из опций, передаваемых ядру загрузчиком. Обычно единственной причиной, по которой уровень загрузки может быть задан как аргумент при загрузке, является необходимость запуска системы в однопользовательском режиме (уровень выполнения 1) для выполнения каких-то административных задач или в случае повреждения диска. Но если уровень выполнения не задан как опция загрузки, то init будет загружать систему на уровень, заданный в файле /etc/inittab .
Если вам нужно узнать, на каком уровне выполнения работает ваша система, то можно воспользоваться командой runlevel. Будучи запущенной без параметров, она сообщает предыдущий и текущий уровень выполнения в виде двух цифр (лучше сказать символов, потому что существуют уровни S и s), разделенных пробелом. Если уровень выполнения не изменялся, то первый символ (идентифицирующий предыдущий уровень) примет значение N.
Изменять уровень выполнения в в работающей системе можно с помощью команды telinit. Естественно, что для ее запуска нужно иметь права суперпользователя. Но об этой команде мы поговорим чуть позже, а пока давайте посмотрим что из себя представляет файл /etc/inittab .
5.2. Файл inittab
Конфигурационный файл /etc/inittab состоит из отдельных строк. Если строка начинается со знака # или пуста, то она игнорируется. Все остальные строки состоят из 4 полей, разделенных двоеточиями:
- id — идентификатор строки. Это произвольная комбинация, содержащая от 1 до 4 символов. В файле inittab не может быть двух строк с одинаковыми идентификаторами;
- runlevels — уровни выполнения, на которых эта строка будет задействована. Уровни задаются цифрами или буквами без разделителей, например, 345;
- process — процесс, который должен запускаться на указанных уровнях. Другими словами в этом поле указывается имя программы, вызываемой при переходе на указанные уровни выполнения;
- action — действие.
В поле action стоит ключевое слово, которое определяет дополнительные условия выполнения команды, заданной полем process . Допустимые значения поля action :
- respawn — перезапустить процесс в случае завершения его работы;
Кодовое слово respawn заставляет init запустить команду, которая указана в этой строке и, если вызванная программа завершает работу, запустить ее снова. Возьмем, например, следующую строку в файле inittab:
Программа getty обеспечивает открытие виртуальной консоли (в данном случае — первой) и запуск в ней программы login, выводящей приглашение ко входу пользователя в систему. Ключевое слово respawn в приведенной строке означает, что после того, как пользователь выйдет из системы, приглашение login будет выведено на первую виртуальную консоль снова.
означает, что init при переходе на 5-ый уровень запустит на выполнение команду /etc/rc.d/rc 5 и будет ожидать окончания работы этой программы прежде чем приступить к чему-либо другому.
Этот список не является исчерпывающим. Более подробно о файле inittab можно узнать из man-страниц init (8), inittab (5) и getty (8).
5.3. Стили начальной загрузки
А теперь давайте вспомним, что существует два разных стиля начальной загрузки операционной системы типа UNIX, происхождение которых уходит корями в историю развития UNIX-систем: так называемый стиль BSD (используемый также в таких системах как FreeBSD, NetBSD и OpenBSD), и стиль System V (или стиль ATT). Различие между ними проявляется в организации и размещении стартовых сценариев (скриптов), обеспечивающих управление процессами загрузки системы. В классических BSD-системах эти файлы хранятся в каталоге /etc и их имена начинаются с префикса «rc». В системах семейства System V файлы сценариев располагаются в каталоге /etc/init.d, а ссылки на них созданы в каталогах /etc/rc0.d, /etc/rc1.d и т.д. Как пишет В.Попов в статье [42] главное отличие стиля BSD от стиля System V состоит в организации скриптов rc: если в системах стиля System V вызывается один и тот скрипт rc, только ему передается параметр, задающий уровень выполнения, то для систем BSD-стиля характерно наличие отдельного скрипта для каждого из уровней выполнения. Вариант организации в стиле System V является более четким и позволяет аккуратнее выполнять останов системы. Если вы хотите подробнее узнать о различиях в двух названных стилях загрузки, прочитайте главу 2 книги [41] или статьи [42]-[45].
Большая часть дистрибутивов Linux использует на этапе загрузки стиль System V. К этому классу относятся Debian, все клоны Red Hat, включая Mandrake и российские дистрибутивы ASPlinux и ALT Linux. В стиле BSD организована загрузка в дистрибутивах Gentoo, Slackware (см. [43]-[45]) и производных последнего). Однако тот или иной стиль сценариев начальной загрузки выдерживается не очень четко. Поскольку стиль System V взят за основу при создании стандарта LSB (Linux Standart Base), дистрибутивы, ранее использовавшие стиль BSD, в последнее время заботятся о совместимости с System V. Slackware обеспечивает такую совместимость начиная с версии 7.0.
Структура каталогов, в которых хранятся инициализационные скрипты, в основных дистрибутивах существенно различается:
Fedora (Red Hat) и Mandriva 2007 |
Knoppix (клон Debian) |
Slackware |
Gentoo |
SuSE |
Как видите, даже в Red Hat и Debian, которые следуют стилю System V, структура каталогов несколько отличается. А SuSE, хотя и происходит от Slackware, движется в сторону стиля System V, по крайней мере в организации структуры каталогов. А вот Red Hat, наоборот, завел скрипт rc.local, напоминающий одноименный сценарий во FreeBSD. В процессе загрузки он выполняется последним. Правда, в последних версиях Red Hat и Fedora Core этот скрипт «пустой», то есть практически не используется. И авторы книги [41] не советуют добавлять в него собственные команды, рекомендуя лучше воспользоваться средствами System V.
Но структура каталогов и названия инициализационных скриптов, может быть, и не самое главное. Более существенно то, что в этих скриптах содержится и как они используются. В листинге 9 приведены выдержки из файла /etc/inittab для нескольких дистрибутивов. Приводится не полный текст файла /etc/inittab, а только по 4 группы самых важных строк, определяющих процесс загрузки. Во всех дистрибутивах кроме приведенных инструкций определяются еще действия по комбинации клавиш ++ и выполняется запуск виртуальных терминалов (только в Fedora Core и SuSE для этого вызываются процессы mingetty, в Gentoo и Slackware — agetty, в Knoppix — /bin/bash -login).
Fedora Core (Red Hat) |
Knoppix (клон Debian) |
Slackware |
Gentoo |
SuSE |
Как видите, во всех случаях порядок действий примерно одинаков:
- Вначале задается уровень выполнения (runlevel).
- Затем выполняются действия начальной инициализации системы, не зависящие от заданного уровня. В разных дистрибутивах для этого вызываются разные скрипты:
- в Fedora Core — /etc/rc.d/rc.sysinit
- в Knoppix — /etc/init.d/rcS
- в Slackware — /etc/rc.d/rc.S (то есть скрипт перехода в Single User mode):
- в Gentoo — /sbin/rc boot
- в SuSe — /etc/init.d/boot
- Затем выполняется скрипт перехода на заданный уровень выполнения. При этом, если в Fedora Core и Gentoo для каждого уровня выполнения задана своя строка, то в Slackware для уровней со 2-го по 5-ый выполняются одни и те же действия.
- Наконец, во всех дистрибутивах, кроме SuSE, отдельная строка задает процедуры запуска графической оболочки.
При использовании стиля System V используется один и тот же скрипт перехода на заданный уровень, а то, что он делает, определяется содержимым каталога /etc/rc.d/rcN.d. Этот каталог содержит перечень ссылок на скрипты запуска тех системных сервисов, которые должны работать на уровне N. Сами скрипты размещаются в каталоге /etc/init.d или /etc/rc.d/init.d.
В отличие от стиля System V в BSD-стиле каждому уровню загрузки соответствует свой сценарий. И сначала всегда происходит переход на уровень S (однопользовательский), а затем уже переход на заданный уровень. Стиль BSD в наиболее чистом виде (из рассматриваемых примеров) представлен в дистрибутиве Slackware.
Поскольку стиль System V взят за основу при создании стандарта LSB (Linux Standart Base), дистрибутивы, ранее использовавшие стиль BSD, в последнее время заботятся о совместимости с System V. Slackware обеспечивает такую совместимость начиная с версии 7.0. Достигается это путем использования сценария rc.sysinit, который производит поиск всех сценариев стиля System V в каталоге /etc/rc.d и выполнит их, если уровень загрузки соответствующий. Это полезно, если вы пользуетесь коммерческим программным обеспечением, которое ориентируется на стиль System V. В то же время, вы можете пользоваться и BSD сценариями.
Можно по-разному оценивать, какой из вариантов организации инициализационных скритпов лучше или хуже. Я считаю, что скорее всего тут просто дело привычки. Но сошлюсь на мнение авторов книги [42], которые высказали следующие мнения о скриптах трех наиболее распространенных дистрибутивов:
- «В сценариях Red Hat непросто разобраться.»
- «Сценарии запуска системы — это та область, в которой SUSE превосходит другие дистрибутивы Linux. Эти сценарии четко организованы, надежны и хорошо документированы.»
- «Сценарии Debian ненадежны, недокументированы и невероятно противоречивы. Печально, но отсутствие стандартных правил организации сценариев запуска привело в данном случае к хаосу.»
Как бы то ни было, разобраться в сценариях запуска возможно, что мы и попытаемся сделать в следующем разделе. А пока рассмотрим в целом, какие задачи выполняет процесс init.
5.4. Действия, выполняемые процессом init
Для примера возьмем файл inittab из дистрибутива ASP Linux 11, то есть будет рассматриваться процедура начальной загрузки в стиле System V.
Листинг 10. Файл /etc/inittab системы ASP Linux 11.
Обработка файла /etc/inittab процессом init начинается в однопользовательском режиме (уровень 1), в котором единственным пользователем является root, работающий с консоли. Первым делом init находит строку, которая определяет, какой уровень выполнения запускается по умолчанию:
Это и будет тот уровень, в котором запустится и будет работать система после загрузки, поэтому естественно, что нельзя указывать в строке initdefault уровни 0 и 6.
Далее init выполняет команды, указанные в строке с ключевым словом sysinit . В нашем примере здесь выполняется скрипт rc.sysinit из каталога /etc/rc.d:
После этого процесс init просматривает файл /etc/inittab и выполняет скрипты, соответствующие однопользовательскому уровню (1 во втором поле строки):
всем уровням (строки с пустым вторым полем):
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
pf::powerfail:/sbin/shutdown -f -h +2 «Power Failure; System Shutting Down»
и уровню, заданному по умолчанию:
pr:12345:powerokwait:/sbin/shutdown -c «Power Restored; Shutdown Cancelled»
Как видим, вначале вызывается скрипт rc из каталога /etc/rc.d. Какой бы уровень выполнения не был задан, вызывается один и тот скрипт, только в зависимости от уровня выполнения ему передается соответствующее значение параметра вызова, так что, например, для 3-го уровня вызов скрипта осуществляется с параметром 3.
Следующая важная функция, которую выполняет этот процесс (на уровнях со 2 по 5) — запуск шести виртуальных консолей (процессов getty), чтобы предоставить пользователям возможность регистрироваться в системе с терминалов. В нашем примере запускается только 3 виртуальных консоли, поскольку еще 3 строки в файле /etc/inittab закомментированы (я сделал это в целях экономии системных ресурсов, мне вполне хватает трех консолей).
Функции, выполняемые скриптами rc.sysinit и rc, а также процесс запуска виртуальных консолей мы подробнее рассмотрим ниже, а сейчас вернемся к краткому обзору действий процесса init .
После завершения загрузки init продолжает работать в фоновом режиме, отслеживая изменения в состоянии системы. Например, если будет подана команда telinit , позволяющая изменить уровень выполнения, процесс init обеспечит выполнение команд, заданных для нового уровня файлом /etc/inittab. Этот файл прочитывается заново и в случае поступления сигнала HUP; эта особенность избавляет от необходимости перезагружать систему для того, чтобы сделать изменения в начальной конфигурации.
Таким образом, процесс начальной загрузки init постоянно находится в оперативной памяти и при получении соответствующих сигналов повторно выполняет цикл чтения из файла /etc/inittab инструкций о том, что нужно делать, причем этот набор инструкций различен для разных уровней выполнения.
Когда суперпользователь останавливает систему (командой shutdown ), именно init завершает все другие исполняющиеся процессы, размонтирует все файловые системы и останавливает процессор.
К вопросу о том, что делает процесс init после завершения процесса загрузки системы, нам, видимо, еще придется вернуться, а пока обратимся к разбору инициализационных скриптов.
Если вы некорректно модифицируете файл /etc/inittab, система может перестать загружаться. Так что перед внесением каких-либо изменений в этот файл по меньшей мере запаситесь загрузочной дискетой и сохраните копию исходного файла на случай фатальных ошибок.
Источник