В.А.Костромин

ОС Linux на Вашем персональном компьютере


Предыдущий раздел.  Вернуться к оглавлению. Следующий раздел. 

Книги и CD по Линукс можно заказать в интернет-магазине Bolero

Процесс загрузки ОС

1. Процесс init
2. Файл /etc/inittab
3. Основные конфигурационные файлы
4. Другие файлы, влияющие на процесс загрузки
5. Процессы, происходящие при логировании пользователя
6. Загрузка в однопользовательском режиме


1. Процесс init

Для того, чтобы добиться желаемой конфигурации системы после загрузки, очень важно представлять, как же происходит процесс загрузки, какие файлы в нем участвуют (используются) и как можно на этот процесс влиять. Эти вопросы и рассматриваются в настоящем разделе.

Как Вы знаете, после включения питания компьютера и завершения тестирования аппаратной части BIOS считывает из первого сектора загрузочного диска короткую программу-загрузчик. Эта программа загружает в память ядро системы, которое хранится в файле vmlinuz-x.y.z-a в каталоге /boot (x.y.z - это номер версии ядра, у меня 2.0.36, а число a не знаю что означает). Ядро включает в себя драйверы аппаратных устройств, конфигурацию ядра можно менять (только не в процессе загрузки, этот вопрос будет рассмотрен отдельно).

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

Точный список этих операций зависит от так называемого уровня выполнения (run level). Уровень выполнения определяет перечень действий, выполняемых процессом init, и состояние системы после загрузки, то есть конфигурацию запущенных процессов. Уровень выполнения идентифицируется числом. В ОС Linux существует 8 уровней выполнения:

0 - остановка системы ;
1 - однопользовательский режим (для специальных случаев администрирования);
2 - многопользовательский режим без NFS (то же, что и 3, если компьютер
        не работает с сетью);
3 - полный многопользовательский режим;
4 - использование не регламентировано;
5 - обычно X11;
6 - перезагрузка системы;
S или s - примерно то же, что и однопользовательский режим, но S и s используются в основном в скриптах.

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

2. Файл /etc/inittab

Первым делом после старта init  считывает свой конфигурационный файл /etc/inittab. Этот файл состоит из отдельных строк. Если строка начинается со знака '#' или пуста, то она игнорируется. Все остальные строки состоят из 4 полей, разделенных двоеточиями:

    id:runlevels:action:process

где

id -  идентификатор строки. Выбирается произвольно, но в файле не может быть двух строк с одинаковыми идентификаторами.

runlevels - уровни выполнения, на которых эта строка будет задействована. Уровни задаются цифрами (без разделителей).

process - команда, которая должна быть запущена.

action - действие. В этом поле стоит ключевое слово, которое определяет, что должен делать демон init, пока выполняется (или после того, как будет выполнена) команда, заданная следующим полем (process): ожидать завершения процесса (wait), выполнять процесс только один раз (once), перезапустить процесс в случае его "смерти" (respawn) или же игнорировать данный элемент (off). Имеется несколько ключевых слов, определяющих действия в особых обстоятельствах. Самое важное из них - sysinit; это ключевое слово обозначает действия, выполняемые в процессе загрузки системы. Другие слова на особые случаи:

powerwait
    Позволяет init-у остановить систему, когда пропало питание. Использование
    этого слова предполагает, что имеется UPS и программное обеспечение, которое
    отслеживает состояние UPS и информирует init о том, что питание отключилось.

ctrlaltdel
    Разрешает init перезагрузить систему, когда пользователь нажимает комбинацию
    control-alt-del на клавиатуре. Обратите внимание на то, что системный
    администратор может определить действия по  C-A-D, например игнорировать
    нажатие этой комбинации (что вполне разумно в системе, где много пользователей).

Этот список не является исчерпывающим. Более подробно о файле inittab можно узнать из man-страниц  init (8), inittab (5), and getty (8).

Обработка файла /etc/inittab процессом init начинается в однопользовательском режиме (уровень 1), в котором единственным пользователем является root, работающий с консоли. Первым делом init находит строку, которая определяет, какой уровень выполнения запускается по умолчанию:

    id:3:initdefault:

(это и будет тот уровень, в котором запустится и будет работать система после загрузки, поэтому естественно, что нельзя указывать в строке initdefault уровни 0 и 7).

Далее init выполняет команды, указанные в строке с ключевым словом sysinit. В стандартной конфигурации здесь выполняется скрипт rc.sysinit из каталога /etc/rc.d. После этого процесс init просматривает файл /etc/inittab и выполняет скрипты, соответствующие однопользовательскому уровню (0 во втором поле строки), всем уровням (строки с пустым вторым полем) и уровню, заданному по умолчанию. В одной из строк, соответствующей уровню по умолчанию, вызывается скрипт rc из каталога /etc/rc.d. Этот скрипт один и тот же для всех уровней (то есть обязательно вызывается, на какой бы уровень выполнения не загружалась система), только в зависимости от уровня выполнения ему передается соответствующее значение параметра вызова, так что, например, для 3-го уровня вызов скрипта осуществляется строкой типа
        l3:3:wait:/etc/rc.d/rc 3
Функции, выполняемые скриптами rc.sysinit и rc мы подробно рассмотрим в следующем подразделе, а сейчас вернемся к краткому обзору действий процесса init.

Следующая важная функция, которую выполняет этот процесс (на уровнях со 2 по 5) - запуск 6 виртуальных консолей (процессов getty), чтобы предоставить пользователям возможность регистрироваться в системе с терминалов. Для этого init порождает процессы, именуемые getty-процессами (от "get tty" - получить терминал), и следит за тем, какой из процессов открывает какой терминал; каждый getty-процесс устанавливает свою группу процессов, используя вызов системной функции setpgrp, открывает отдельную терминальную линию и обычно приостанавливается во время выполнения функции open до тех пор, пока машина не получит аппаратную связь с терминалом. Когда функция open возвращает управление, getty-процесс исполняет программу login (регистрации в системе), которая требует от пользователей, чтобы они идентифицировали себя указанием регистрационного имени и пароля. Если пользователь зарегистрировался успешно, программа login наконец запускает командный процессор shell и пользователь приступает к работе. Этот вызов shell'а именуется "login shell" (регистрационный shell, регистрационный интерпретатор команд). Процесс, связанный с shell'ом, имеет тот же идентификатор, что и начальный getty-процесс, поэтому login shell является процессом, возглавляющим группу процессов.
Если пользователь не смог успешно зарегистрироваться, программа регистрации завершается через определенный промежуток времени, закрывая открытую терминальную линию, а процесс начальной загрузки порождает для этой линии следующий getty-процесс. Процесс начальной загрузки делает паузу до получения сигнала об окончании порожденного ранее процесса. После возобновления работы он выясняет, был ли прекративший существование процесс регистрационным shell'ом и если это так, порождает еще один getty-процесс, открывающий терминал, вместо прекратившего существование.

После завершения загрузки init продолжает работать в фоновом режиме, отслеживая изменения в состоянии системы. Например, если будет подана команда telinit, позволяющая изменить уровень выполнения, процесс init обеспечит выполнение команд, заданных для нового уровня файлом /etc/inittab. Этот файл прочитывается заново и в случае поступления сигнала HUP; эта особенность избавляет от необходимости перезагружать систему для того, чтобы сделать изменения в начальной конфигурации.
Таким образом, процесс начальной загрузки init  выполняет бесконечный цикл чтения из файла /etc/inittab инструкций о том, что нужно делать, причем этот набор инструкций различен для разных уровней выполнения.

Когда суперпользователь останавливает систему (командой shutdown), именно init  завершает все другие исполняющиеся процессы, размонтирует все файловые системы и останавливает процессор.

Замечания: 1. В приведенном описании опущены многие важные детали. Более подробное описание можно найти в man-страницах по init (8), inittab (5) и getty (8), а также в документах "Linux Documentation Project's Serial HOWTO".

2. Если Вы некорректно модифицируете файл /etc/inittab, система может перестать загружаться. Перед внесением изменений по меньшей мере запаситесь загрузочной дискетой и сохраните копию исходного файла на случай фатальных ошибок.

3. Основные конфигурационные файлы.

Если Вы прочитали предыдущий подраздел (или если смотрели файл /etc/inittab), то представляете, что в обычной ситуации процесс init  помимо запуска процессов getty выполняет 2 основных действия:
- запускает скрипт rc.sysinit из каталога /etc/rc.d;
- запускает скрипт rc из того же каталога /etc/rc.d с опцией, равной уровню выполнения (обычно rc 3).
В файле rc.sysinit содержатся команды инициализации системы, в том числе команды установки системных переменных, загрузки таблиц раскладки клавиатуры (командой loadkeys) и системного фонта (consolechars), монтирования и проверки файловых систем, загрузки модулей, задания предпочитаемой графической оболочки  и т.д.

Прежде чем рассматривать функции, выполняемые скриптом rc, надо сказать несколько слов о каталоге /etc/rc.d. Этот каталог вообще играет важную роль в процессе загрузки, поскольку он содержит основные скрипты (программы на языке командного процессора shell), которые служат для организации процесса загрузки.

Каталог rc.d содержит следующий набор подкаталогов :
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
init.d

Подкаталог init.d содержит по одному скрипту для каждой из возможных в системе служб (под службами здесь имеются в виду такие вещи как NFS, sendmail, httpd и т.п.). Если Вы просмотрите (например, с помощью команды ls -l) содержимое подкаталогов rcX.d, то увидите, что в этих подкаталогах содержатся не файлы, а только ссылки на файлы скриптов, находящиеся в других каталогах, а именно, за редким исключением, в каталоге /etc/rc.d/init.d. Названия этих ссылок имеют имена, начинающиеся либо с буквы K, либо с буквы S.

Теперь вспомним, что процесс init после скрипта rc.sysinit запускает скрипт rc с опцией, равной заданному уровню выполнения. Этот скрипт предназначен в общем случае для перевода системы из одного уровня выполнения на другой. В процессе начальной загрузки этот скрипт переводит систему из однопользовательского режима на уровень, задаваемый по умолчанию. Общий алгоритм работы rc состоит в следующем. При переходе на уровень X сначала просматривается каталог rcX.d и для всех ссылок, которые начинаются на K, вызываются файлы, на которые идет ссылка, с опцией stop, то есть осуществляется останов соответствующих служб (которые не должны работать на данном уровне выполнения). Затем запускаются службы, которые на данном уровне выполнения должны быть запущены. Это осуществляется путем последовательного просмотра ссылок, которые начинаются с символа S, и запуска соответствующих скриптов с опцией start.
Из сказанного ясно, что буквы (символы) S и K, с которых начинаются имена ссылок в подкаталогах rcX.d, происходят от start и kill, соответственно. Заметим еще, что после S и K в именах ссылок стоят двузначные номера, которые служат для задания порядка запуска скриптов.

Одна из последних ссылок, используемых скриптом rc на уровнях 2-5, является ссылка на скрипт /etc/rc.d/rc.local. Как сказано в самом этом файле, этот скрипт выполняется после всех других скриптов в процессе инициализации системы, поэтому если Вы хотите, чтобы в процессе загрузки были выполнены какие-то дополнительные команды или Ваши персональные настройки, то их целесообразно поместить именно сюда.
 

4. Другие файлы, влияющие на процесс загрузки

Все важнейшие файлы конфигурации расположены в каталоге /etc:

/etc/fstab - содержит информацию об автоматическом монтировании файловых систем;
/etc/skel - образцы файлов конфигурации, используются при вводе новых пользователей;

Менее важные файлы конфигурации:

/etc/issue - сообщение, выдаваемое системой до приглашения "login:";
/etc/motd - аналогично, но выдается после входа в систему;
 

5. Процессы, происходящие при логировании пользователя

Последовательность событий при полной регистрации выглядит так:

Основные файлы

/etc/profile - глобальный файл профилей, устанавливает пути и другие важнейшие переменные;
/etc/passwd - различная регистрационная информация, включая пароли;
/etc/bashrc - глобальный файл конфигурации bash (ваша оболочка по умолчанию)
/домашний каталог/.* - ваши личные файлы конфигурации. Если их нет, то после входа в систему будут прочитаны глобальные файлы, содержащие значения "по-умолчанию".

Если Вы хотите, чтобы при логировании пользователя выполнялся какой-то скрипт, то можно вызов этого скрипта поместить в ~/.profile. Это может сделать и сам пользователь.

Если требуется чтобы пользователь не мог отменить выполнение этого скрипта или команды, то впишите в ./etc/profile что-то типа

if test `id -u` -eq 534; then   #где 534 - user id
        echo hi                 #сюда Вы помещаете нужную команду 
	fi 
или, если пользователя называть по имени,
if test $USER = root; then
        echo Hi root
	fi 
Эти команды будут исполняться только при входе пользователя в систему и он не сможет запретить их.

6. Загрузка в однопользовательском режиме

Вы можете заставить процесс init  загрузить систему на уровне выполнения, отличном от того, который загружается по умолчанию. Эта возможность оказывается просто необходимой в тех случаях, когда с системой что-то случилось и нормальная загрузка стала невозможной. В такой ситуации надо перевести систему в однопользовательский режим, для чего задать в командной строке загрузки ядра (в ответ на приглашение LILO boot:) аргумент single или emergency. Это позволяет загрузить систему в однопользовательском режиме (уровень выполнения 1), в котором в системе работает только один пользователь - администратор и запускается только очень небольшое число самых необходимых системных служб (system services) -- включая logins. (Другим способом перевода системы в однопользовательский режим является применение команды telinit).

Однопользовательский режим необходим для выполнения административных задач, таких как запуск fsck  в разделе /usr, - для этого требуется, чтобы раздел был размонтирован, а этого нельзя сделать, пока не будут отключены почти все системные службы. Запуск fsck  в разделе /usr обычно требуется тогда, когда файловая система разрушена и тогда любые дальнейшие действия в разрушенной системе могут привести к полному краху, а значит fsck должна быть запущена как можно скорее. Обычно о необходимости перехода в однопользовательский режим говорит то, что fsck не может автоматически восстановить файловую систему при загрузке. Такое случается относительно редко, обычно при выходе из строя жесткого диска или при попытках установить какую-либо экспериментальную версию ядра, но все же об этом надо знать, чтобы не растеряться в затруднительной ситуации.

Из соображений безопасности нормально сконфигурированная система при загрузке оболочки в однопользовательском режиме запросит пароль пользователя root. Это очевидно, так как иначе было бы очень просто задав соответствующую строку загрузчику LILO, войти в систему как root.


Предыдущий раздел.  Вернуться к оглавлению. Следующий раздел. 

В.А.Костромин
Последние изменения
в содержание файла внесены
2 декабря 2000 г.
TopList Aport Ranker