Файл init за что отвечает
Самым первым процессом является программа init. И от того, каким образом она сконфигурирована, зависит дальнейшая загрузка системы.
Ядро Linux при старте обязательно монтирует корневую файловую систему (обычно в режиме только для чтения). Поэтому при запуске init может быть запущен (для этого необходимо получить доступ к файлу программы) и может прочитать свой конфигурационный файл /etc/inittab.
Процесс запуска init каждый, кто знаком с языком программирования C, может посмотреть в исходных кодах ядра, в файле init/main.c, для остальных (а также просто ленивых) скажу, что:
когда наступает время породить первый процесс, то первым делом ядро пытается запустить программу, указанную опцией rdinit=;
Никогда не выносите в отдельный раздел директории /bin, /sbin, /etc, /dev. Файлы находящиеся в них могут потребоваться при старте системы. Ярким примером являются программа init и ее конфигурационный файл /etc/inittab.
Действия
В таблице приведены некоторые ключевые слова, которые можно использовать в поле действие.
initdefault | Определяет уровень выполнения по умолчанию во время загрузки системы. |
sysinit | Программа будет выполняться при запуске системы самой первой. init будет ожидать её завершение, прежде чем начнет выполнение следующих в списке программ. |
wait | Программа запускается один раз. init будет ожидать ее завершение, прежде чем начнет выполнение следующих в списке программы. |
once | Программа запускается один раз. init не ждет её завершения. |
ctrlaltdel | Определяет программу, которая будет запущена при нажатии на клавиши "Ctrl+Alt+Del". |
powerfail | Определяет программу, которая будет запущена при получении процессом init сигнала сбоя питания. |
powerokwait | Определяет программу, которая будет запущена при получении процессом init сигнала восстановления питания. |
respawn | Процесс будет запущен. init не будет ожидать окончания процесса и начнет обрабатывать следующие в списке строки. Если процесс завершит свою работу – init запустит его снова. |
Из конфигурационного файла можно сделать вывод, что в Slackware Linux на уровне выполнения 3, init запускает следующие программы:
Посмею предположить, что каждого интересовало хоть когда-либо то, что происходит за занавесом заставок и загрузочных экранов с момента включения питания компьютера к моменту, когда предлагается войти в систему.
Я предлагаю вам познакомиться со следующими уровнями типичной загрузки Linux:
1. BIOS
- BIOS отвечает за базовый ввод/вывод данных с устройств/на устройства.
- Делает некоторые проверки целостности устройств. К тому же, за тестирование работоспособности электроники отвечает POST (Power-on self-test, он же «тест на адекватность себя самого», выполняющийся как этап пре-загрузки), который управляется BIOS
- Ищет, загружает и выполняет программу-загрузчик ОС
- Берет загрузчик из флопика, сидюка или жесткого диска. Во время загрузки BIOS'а вы можете нажать на кнопку (обычно это F12 или F2 или Del, зависит от платформы), если вам требуется внести некоторые изменения касательно настройки железа.
- Как только загрузчик был обнаружен и загружен в память, BIOS передает управление ему.
- Короче говоря, BIOS загружает и выполняет загрузочную запись (MBR).
2. MBR
- MBR — это главная загрузочная запись, хранящаяся на жестком диске
- Она размещена в 1-м секторе загрузочного диска, например /dev/hda или /dev/sda
- MBR занимает меньше, чем 512 байтов. Она состоит из трех компонентов: 1) главная загрузочная информация, «живущая» в первых 446 байтах; 2) информация о таблице разделов — в следующих 64 байтах; 3) и последние 2 байта нужны для проверки корректности mbr.
- Она содержит информацию о GRUB'е (или LILO).
- Простыми словами — MBR загружает и выполняет загрузчик GRUB.
3. GRUB
- GRUB — Grand Unified Bootloader.
- Если в вашей системе установлено более, чем одно ядро, у вас есть возможность выбирать, которое из них должен выполняться
- GRUB отображает
красивую анимацию plymouthзаставку, и, подождав несколько секунд интерактивного воздействия пользователя, если он не нажал ни одной клавиши, он загружает ядро, установленное по умолчанию в файле конфигурации grub. - GRUB понимает, что такое файловая система (древние загрузчики Linux'а, например, LILO этого не понимают).
- Конфигурационный файл Grub обычно лежит по пути /boot/grub/grub.conf (так же /etc/grub.conf может быть символьной ссылкой на него). Вот пример файла конфигурации для CentOS:
4. Ядро или Kernel
- Ядро монтирует файловую систему в соответствии с настройкой «root=» в фале grub.conf
- Выполняет программу /sbin/init
- Поскольку init — это первый процесс, запущенный ядром Linux, поэтому она имеет идентификатор процесса (PID) №1. Можете выполнить «ps -ef | grep init» и убедиться в этом.
- initrd — это Initial RAM Disk, он же временный диск в оперативной памяти
- initrd используется самим ядром в качестве временной корневой файловой системы, пока kernel не загрузится в реальную примонтированную файловую систему. Этот временный диск также содержит необходимые для загрузки драйверы, позволяющие получить доступ к разделам дисков и другому оборудованию
5. Init
- Смотрит в файл /etc/inittab для того, чтобы определить уровень выполнения (run level).
- Есть следующие уровни выполнения:
- 0 – прервать выполнение
- 1 – Однопользовательский режим, так называемый «Single user mode», или иными словами, консоль восстановления
- 2 – Многопользовательский режим без поддержки NFS
- 3 – Полноценный многопользовательский режим
- 4 – не используется
- 5 – X11
- 6 – перезагрузка
6. Уровень выполнения программ (Runlevel)
Вот и все. Возможно, некоторым из вас это не ново и особого интереса не было при чтении статью, поскольку она более ориентирована на начально-средний уровень знакомства з Линуксом.
В таком случае могу лишь сказать, что «повторение — мать учения» (с).Дополнения, исправления, уточнения
-
: «Ну скажем прямо — так грузятся далеко не все дистры». С ним согласилось большинство, отмечая и bsd-style init, u-boot, и хоть initrd в статье пропущен, стоить заметить, что он нужен ядру не во всех дистрибутивах. Также отмечено, что в slackware поддержка rc.d осуществляется только в качестве совместимости, а встраиваемые системы грузятся иначе. На декстопах иногда бывает EFI, а кроме того Linux популярен в мире embedded и там ещё куча разных платформ. Линукс в телефоне вообще иначе грузится. , ссылая на википедию: Еще хочется сделать замечание по поводу MBR, первого сектора и пр. Все несколько усложнилось за последние годы. Сейчас уместней говорить о EFI.
init (сокращение от англ. initialization — инициализация) — программа в UNIX и Unix-подобных системах, которая запускает все остальные процессы. Работает как демон и обычно имеет PID 1. Обычно (согласно Filesystem Hierarchy Standard) располагается по пути /sbin/init.
Файл /etc/inittab
Как уже было упомянуто выше, работа процесса init управляется с помощью файла /etc/inittab. Вот пример этого файла (без комментариев):
В первой строке описан терминал и его конфигурация по умолчанию. Сначала в этом файле описываются уровни инициализации. Затем инициируются виртуальные консоли. Запись инициализации консолей состоит из полей, разделенных двоеточием и выглядит следующим образом:
- 1 — порядковый номер консоли
- 2345 — номера уровней инициализации, для которых консоль инициализируется
- respawn — этот параметр означает, что init должен перезапустить обслуживающий консоль процесс после выхода из сеанса или в случае краха.
- /sbin/mingetty tty6 — программа (с указанием параметров), которая будет обслуживать консоль.
Таким образом, вы легко можете создать свой уровень инициализации (под номером 4 или 7, 8…), просто исправив файл /etc/inittab и создав необходимые ссылки в каталоге /etc/rc.d/rc*.d
Заключение
В следующей части я расскажу, откуда берутся образы system.img, userdata.img и cache.img и рассмотрю безопасность на уровне Native user space. Как всегда приветствуются исправления, дополнения, а так же предложения, о чем написать. И хотя у меня уже есть некоторый план, о чем писать в следующих статья, я готов его подкорректировать.
В прошлый раз мы говорили о том, что происходит при загрузке Linux: вначале стартует загрузчик, он загружает ядро и развертывает временный диск в оперативной памяти, ядро запускает процесс init, init находит настоящий корневой диск, производит такой хитрый переворот - вместо временного виртуального диска на это же самое место в корневой каталог монтируется реальный диск, с этого реального дисков процесс init загружает в себя другой init, который есть на этом реальном диске. После всех этих операций UNIX переходит в состояние обычной работы.
В этой лекции я расскажу, что делает классическая программа init в сочетании со скриптами rc.d в стиле System V (Систем пять). System V - это классическая версия UNIX на которой построены коммерческие UNIX.
Судя по названию, rc.d это некий каталог. Есть такая традиция UNIX - если вся конфигурация чего-либо умещается в один файл, и он называет config, то при разбиении его на отдельные файлы, которые подключаются к основному, создают каталог с аналогичным именем и добавляют к имени .d – config.d. Буква d означает, что это директория и там лежат вспомогательные части конфигурационного файла. У формата конфигурационных файлов программы init есть две традиции: вариант System V, в котором каждая деталь конфигурации держится в отдельном файле в каталоге rc.d, и традиция BSD систем, в которой есть один файл /etc/rc, содержащий много скриптов и переменных, которые отвечают за поведение системы.
В любом случае, при старте системы у нас создается процесс с PID=1, в котором запущена программа, которая называется init. Как вы видели в прошлый раз, если программу init убить, то ядро впадает в панику и прекращает всяческую работу.
Классический System V init читает файл /etc/inittab и выполняет ряд предписаний, которые прописаны в этом файле. Inittab этот текстовый файл каждая строка которого, это, по сути дела, одна команда или какое-то правило поведения. Inittab выглядит так:
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
Вначале строки стоит метка. В чем большой смысл этой метки я не очень понимаю. Можно считать, что это простой текст и все. Вторым пунктом стоит либо так называемый уровень загрузки, либо пустое значение. Уровень загрузки — это либо одно число от 0 до 6, либо список чисел через запятую. Дальше идет некое действие. Действия бывают следующие: wait, respawn, sysinit, ctrlaltdel. Есть и другие действия, но это самые используемые. Наконец, в конце строки написана некая команда с именем исполняемого файла и аргументов, которые этой команде надо передать.
Действие sysinit выполняется однократно при старте системы.
Действие wait означает, что необходимо запустить команду, дождаться пока она закончится и только после этого продолжить обработку следующих строк. Не знаю, могут ли запускаться такие действия в параллель. Скорее всего, нет.
Действие respawn означает, что надо запустить программу и не дожидаясь ее завершения, перейти в дальнейшем действиям. Если эта программа в последующем завершится, то необходимо ее рестартовать.
Итак, есть однократное выполнение с ожиданием результатов и многократное выполнение в асинхронном режиме – запустились, дождались пока закончить, запустили слова.
Уровни загрузки — это некая условность, которая позволяет управлять загружаемыми службами. Ближайший аналог в windows – это загрузка в безопасном режиме, когда грузится только ограниченное число драйверов и стартует минимальное количество служб, загрузка с отладкой, когда каждое действие дополнительно протоколируются и обычная полноценная загрузка.
В Linux по традиции выделяется 6 вариантов загрузки. Это деление довольно условно.
0 и 6 это выключение. 0 - полное выключение электричество, а 6 - режим перезагрузки.
4 в Linux вообще пропущен
Остаются четыре уровня загрузки:
1 - однопользовательский режим. Если передать загрузчику ключевое слово single, то мы окажемся в однопользовательском режиме, где запущен только один процесса и это шелл администратора системы. Этот режим используется для восстановления системы.
3 - нормальный многопользовательский текстовый режим, когда запущены все службы, работает сеть, работают все драйверы.
5 - то же самое что и 3, но с запуском x window - графического интерфейса.
Можно считать, что между уровнями есть некоторая последовательность переходов:
режим 2 включает себя 1 + многопользовательский режим. 3 включает 2 + монтирование сетевых файловых систем. Наконец, 5 включает в себя 3 + запуск графической подсистемы. Будет ли это реализовано последовательно или нет - это проблема дистрибутива. Вообще говоря, администраторы могут самостоятельно настроить файл inittab так, чтобы эти режимы запускались последовательно, а можно сделать так чтобы все было абсолютно независимо - переключаясь в очередной режим, убираем все что было сделано на предыдущем шаге, и настраиваем все с нуля.
Рассмотрим строки реального файла. Они очень просты.
Запускается какая-то программа, которая должна выполнить все необходимые действия, которые ожидаются на третьем уровне. Наверно, на третьем уровне нужно настроить сетевые интерфейсы, запустить драйвер терминалов, стартовать какие-то службы. Только после того, как всё этого завершится мы сможем работать в системе. Поскольку надо дождаться завершения запуска, мы выбираем действие wait.
Программа запуска называется rc и запускается с номером уровня в качестве параметра. Сама программа init достаточно простая. Она умеет построчно читать свой файл с простым синтаксисом и стартовать новые процессы, запуская какие-то вспомогательные программы. Вся логика уровней загрузки спрятана в скрипте rc. Запустив rc с параметром 3 мы перейдем на третий уровень, с параметром 5 - на пятый.
Программа rc тоже очень простая. Это скрипт который выполняет все файлы в каталогах, соответствующих уровню загрузки, например, /etc/rc3.d/. В этих каталогах находятся исполняемые файлы, которые принимают один параметр - либо start, либо stop. Если файл запущен с параметром start, то он стартует службу, если с параметром stop, то останавливает её. Например, network start будет настраивать сетевые интерфейсы, а network stop будет переводить интерфейсы в выключенное состояние. Кроме сетевых интерфейсов есть скрипты подключения/отключение сетевых файловых систем, запуска/остановки сервисов и т.д.
Имена файлов в каталогах построенным по определенным правилам. Они начинаются либо с буквы K либо с буквы S, за которыми идет число и имя службы.
Скрипт rc просматриваем содержимого каталога rc3 и выбирает оттуда все файлы которые начинаются с буквы K (kill). Файлы упорядочиваются в порядке возрастания номера и выполняются с параметром stop. Потом те же действия выполняются с файлами на букву S (start), которые запускаются с параметром start. Вот в общем и вся процедура перехода на определенный уровень.
Можно предположить, что в каталоге /etc/rc0.d/ лежат только файлы, начинающиеся на букву K, поскольку при выключении надо все остановить, а в каталоге /etc/rc1.d/ будет один файл на буку S для запуска консоли администратора.
Для простоты программирования есть отдельный каталог /etc/init.d/, в котором лежат те же самые файлы только без буквы цифр в начале имени. На самом деле, файлы в каталогах уровней это просто символические ссылки на основные файлы. Так /etc/rc3.d/S10apache это ссылка на файл /etc/init.d/apache. Буквы и цифры в названии ссылок нужны для того, чтобы скрипт rc вызвал их в нужном порядке и с нужными аргументами.
В системах, которые построены по такому принципу, чтобы стартовать или остановить какую-либо службу в каталоге /etc/init.d/ надо найти файл который, который ей соответствует, и запустить его с параметром start или stop. Чем не нравится запускать службы именно таким способом - явно вызывая скрипты. Дело в том, что в командной строке linux замечательно работает автодополнение. С его помощью очень быстро можно ввести путь до файла запуска.
Чтобы спрятать от пользователя конкретную реализацию поверх системы скриптов и символических ссылок написаны две вспомогательные программы.
Программа chkconfig позволяет манипулировать символическими ссылками на соответствующие скрипты. Чтобы посмотреть, что стартует, а что останавливаться на каждом из уровней можно воспользоваться командой ls и выдать список скриптов в соответствующем каталоге, но проще воспользоваться командой chkconfig –list. Программа chkconfig пробегает по всем каталогам rc и выдает список того что стартует, а что останавливается на каждом уровне. Если мы хотим, чтобы при старте системы у нас что-то автоматически стартовала определенная службу мы выполняем chkconfig on и скрипт создает ссылку для запуска в нужном каталоге и с правильным именем. Запуск chkconfig off приводит к удалению ссылки для запуска и созданию ссылки для остановки. Таким образом программа chkconfig позволяет управлять списком служб, которые стартуют в момент старта системы.
Ещё одна программа - service используется для ручного запуска и остановки служб. Service это обертка, которая позволяет не обращаться напрямую к скрипту, а указать имя службы и сказать хотим мы ее стартовать или остановить. В bash, который я использую, нет автодополнения для команды service, поэтому мне проще набрать путь к скриптам.
В стартовых скриптах аргументы start и stop должны обрабатываться обязательно. Кроме того, можно придумать какие-то свои аргументы, которые будут делать что-то полезное.
В большинстве скриптов реализована опция status, которая показывает запущена служба или нет. Когда мы выполняем start, то скрипт после успешного запуска службы получает ее идентификатор PID и записывать его в определенный файл. По команде stop файл удаляется. Обычно такие файлы создаются в каталоге /var/run/. Команда status проверяет есть ли такой файл. Его нет, то сообщает, что служба не запущена. Если файл есть, то она извлекает из него идентификатор процесса и проверяет текущий список процессов. Если этот идентификатор присутствует все запущено, если программа по каким-то причинам поломалась, то статус выдаёт, что была сделана попытка запустить эту службу - файл существует, но сама служба не запущена.
Опция restart последовательно выполняет внутри скрипта две команды – сначала stop, а потом старт. Это совершенно необязательная команда - просто удобная. Наконец, есть службы, которые позволяет на ходу перечитать какие-то конфигурационные файлы. Для них добавляют команду reload, задачей которой является отправка службе сигнала о том, что конфигурация изменилась. Отдельный случай, команды save и load для сохранения конфигурации брандмауэра.
Если администратор системы вместо остановки или старта отдельных службы хочет всю систему перевести на определенный уровень, то этого можно достичь одним из двух способов. Можно вызвать прямо программу /sbin/init. Если ее вызвать с определенным числом в качестве параметра, то она выполнит все инструкцию из файла inittab, для которых прописывал соответствующий уровень. Если запустить, например, /sbin/init 1, то init найдет в своем конфигурационном файле все строчки, в которых есть уровень 1 и выполнит их. В некоторых системах команда shutdown реализована как /sbin/init 0, поскольку нулевой уровень соответствует остановке системы. В последнее время для перехода между уровнями появилась специальная программа под названием telinit, которая является ссылкой на init. Её задача – переслать процессу init сигнал о том, что администратор желает перейти на определенный уровень. telinit q сообщает init о том, что надо перечитать файл inittab. В старых системах это достигалось посылкой сигнала SIGHUP процессу с PID=1 (kill –HUP 1).
Ещё несколько строк в inittab, это запуск терминалов
Для того, чтобы обеспечить диалоговую доступ к системе, вы inittabе может присутствовать некоторое количество строчек такого рода. 2345 это уровни, на которых надо запускать команду, respawn означает, что программу надо перезапускать в случае завершения. Программа getty – это программа управления терминалом. Традиционно терминал в UNIX называется телетайпом, поскольку первыми терминалами были электрические пишущие машинка. Соответственно, tty это сокращение от телетайпа. Mingetty – программа, которая умеет работать с виртуальными терминалами на персональном компьютере. Она умеет настраивать драйвер терминала, а в качестве параметров получает имя устройства терминала, который надо настроить. В каталоге /dev/ есть файл устройства tty1, который соответствует первому виртуальному терминалу. Если бы у нас был модем и мы хотели бы инициализировать его момент загрузки, то могли бы вызвать getty с параметром ttyS0, который соответствует порту COM1. При инициализации модема можно было бы задать дополнительные параметры: скорость соединения 19200 бод, 7 или 8 бит в байте, четность, количество стоп-битов.
S0:2345:respawn:/sbin/getty ttyS0 19200 8 n 1
В прошлый раз я рисовал цепочку, в которой процесс вызовом fork делаются свою копию, дочерняя копия вызовом exec загружает в свою память другую программу, а после завершения сообщает об этом родительскому процессу.
Текстовые пользовательские сеансы устроены на таких цепочках: сначала init делает свою копию и запускает в ней программу mingetty. Mingetty инициализирует терминал и клавиатуру, а потом запускает в том же процессе программу login. Login выводит на экран приглашения на ввод имени и пароля и, если все прошло успешно то назначает себе привилегии пользователя и в том же процессе, затирая самого себя, запускает интерпретатор пользователя, например, bash. Когда пользователь набирает команду exit, то интерпретатор завершает жизненный путь этого процесса. Когда процесс завершается, init получает об этом сигнал. Init смотрит, что полагается делать, видит действие respawn, снова запускает программу mingetty, которая заново инициализирует терминал и все повторяется. Таким образом каждый сеанс находится внутри одного процесса. Как только мы вышли из сеанса наш процесс закончился и тотчас же запустилась программа, которая почистит за нами терминал и восстановит все настройки по умолчанию.
В файле inittab есть есть ещё одно специальное ключевое слово initdefault - уровень по умолчанию. Если через ядро init получил параметр single, то мы загрузимся на уровень 1. Если через загрузчик ничего не передали, то используется значение по умолчанию. Если после установки графической оболочки оказалось, что наш компьютер слабоват для графики, то можно установит уровень по умолчанию на 3, и после следующей перезагрузки мы попадаем на третий уровень - то есть в текстовый режим. Установили систему без графического режима, потом доустановили все пакеты для x window, поменяли уровень по умолчанию на 5 и после следующей перезагрузки попали сразу в графический режим.
В этой системе скриптов иногда хочется сделать что-то свое, например, при старте удалить все файлы в каталоге /tmp/. Для этого есть отдельный файл под названием /etc/rc.local, который запускается после всех остальных. Это просто скрипт без параметров, в который можно прописать всё, что угодно. Например, на одном из моих роутеров в момент старта системы в этом файле прописываются таблицы маршрутизации. Мне было лень искать где находятся соответствующие стандартные скрипты из дистрибутива и проще оказалось прописать команды в rc.local.
init в других ОС
В Windows NT роль init играет smss.exe. В Solaris 10 вместо init применяется Service Management Facility. /* init в Solaris 10 запускает и, в случае необходимости, перезапускает SMF (init initiates the core components of the service management facility, svc.configd(1M)and svc.startd(1M), and restarts these components if they fail). Т.е. можно сказать, что в Solaris 10 большая часть функций init выполняется с помощью SMF. */
Файловая система Android
Для начала давайте рассмотрим структуру файловой системы Android. Хотя Android и базируется на Linux kernel, привычную нашему глазу структуру файловой системы мы здесь не увидим. Давайте запустим эмулятор и посмотрим, что у нас есть. Для этого выполним комманду:
В моем терминале для эмулятора на Android 4.2 я вижу следующий результат:
Я отмечу здесь только главные директории и те, которые нам пригодятся в будущем. В Интернете можно найти описание и предназаначение других директорий. Можно заметить, что некоторые директории такие же, как и в Linux, например, /dev, /proc, /sys, /mnt, /etc И их предназначение в основном такое же, как и в Linux. Кстати, отметьте, что мы не видим /bin и /lib директорий. Где они скрылись, я расскажу чуть позже.C другой стороны можно заметить директории, которых в Linux вообще нет. Среди них нас интересуют /data, /system, /cache, /init, /init.rc Давайте рассмотрим их назначение поподробнее.
/system Это главная директория, где хранятся неизменяемые компоненты Android системы. Если проводить аналогию, то эта папка похожа на папку C:\windows\, доступную только для чтения. Т.е. изменять данные в этой директории мы не можем. Как раз здесь можно найти директории /bin и /lib, где хранятся различные исполняемые файлы и shared libraries. Кроме того, здесь же лежат системные приложения, которые встроены в операционку и которые, по умолчанию, нельзя удалить. Содержимое этой директории формируется во время компиляции операционной системы.
/data Т.к. /system у нас доступна только для чтения, то должна быть директория где хранятся изменяемые данные. /data как раз ею и является. Например, в эту директорию в /data/app сохраняются apk файлы устанавливаемых приложений, а в /data/data хранятся их данные (эту директорию мы подробно рассматривали в прошлой статье).
/cache Это просто временное хранилище. Также в эту директорию сохраняются, а потом из неё запускаются системные обновления.Чтобы понять, что такое /init файл и для чего нужны непонятные файлы с расширением *.rc, рассмотрим процесс загрузки системы.
Формат файла /etc/inittab
id — идентификатор, один или два символа. Поле должно быть уникальным. Никак не влияет на работу современной версии программы init.
run_level — список уровней выполнения, на которых будет выполняться программа. Поле может быть пустым.
action — определяет особенности выполнения программы. В этом поле можно писать только заранее определенные слова.
Init рассматривает строки в том порядке, в котором они написаны в файле. Предположим, что мы хотим перевести систему на третий уровень выполнения и запускаем init следующим образом:
Программа начнет выполнять только те строки, в поле run_level которых будет присутствовать цифра 3. То есть, будут запускаться программы, описанные в поле process, но с некоторыми оговорками, определяемые полем action.
Поскольку программу писали люди, родным языком для которых является английский, они внесли некоторые особенности английской грамматики в программу. В английском языке есть правила, но так же существует большое количество исключений из этих правил. То, что я написал в предыдущем абзаце — это правило, но у него есть несколько исключений.
Давайте рассмотрим конфигурационный файл inittab на примере дистрибутива Slackware Linux. Ниже показано содержимое этого файла, за исключением комментариев и пустых строк.
При старте системы ядро запускает программу init без указания уровня выполнения. То есть, просто
Программе каким то образом необходимо узнать, какие строки в этом случае выполнять. Какой уровень выполнения использовать? Для указания уровня выполнения используется строка
Это первое исключение из общего правила. Как видите поле process пустое. В поле action написано ключевое слово initdefault, которое означает, что в поле run_level написан уровень выполнения используемый по умолчанию.
Дальше мы будем рассматривать файл с учетом того, что система стартует на третьем уровне выполнения.
В следующей строке нас ждет сразу два исключения из общего правила!
Во первых, в поле run_level стоит буква S, да и action sysinit, не просто так тут написана.
Начнем с буквы S. Когда ядру при загрузке передается параметр single, ядро запускает программу init таким образом, что она перестает реагировать на все строки, кроме тех, в поле run_level которых стоит буква S. Обычно дистрибутивы сконфигурированы таким образом, что бы в этом случае система запускалась на уровне выполнения 1 (single user mode).
Действие sysinit означает, что программа, описанная в поле process будет выполняться только при старте системы, и init будет ожидать ее завершения, прежде чем начнет выполнять следующие строки. Таким образом, программа /etc/rc.d/rc.S будет выполняться только при старте системы. При переходе с одного уровня выполнения на другой она запускаться не будет.
Строка на третьем уровне выполнения работать не будет, мы ее пропустим.
В поле run_level присутствует цифра три, поэтому программа /etc/rc.d/rc.M будет запущена. Действие wait означает, что init будет ожидать завершение выполнения программы, прежде, чем начнет выполнять следующие строки из файла inittab. Таким образом, второй при старте системы будет запущена программа rc.M.
В поле run_level этой строки нет ни одной цифры, значит она не будет выполняться при старте системы. Как то странно при старте сразу запускать программу shutdown. Но в поле действие присутствует интересный параметр: ctrlaltdel. Он заставляет init следить за нажатием комбинации клавиш Ctrl(левый)+Alt(левый)+Del. И если кто то их нажмет, выполнит программу, указанную в поле process.
Обратите внимание на то, что не имеет значения, залогинился пользователь в систему или нет. Любой проходящий мимо человек может нажать эту комбинацию клавиш и система будет перезагружена.
Эти две строки никакого отношения к третьему уровню выполнения не имеют, поэтому мы их пропускаем. никакого
Поле run_level в этих строках пустое, поэтому при старте системы они работать не будут. Но, init их запомнит. Для того, что бы эти строки заработали, необходимо, что бы у вас был интеллектуальный UPS, подключенный к вашей машине. А так же запущена программа, которая понимает команды UPS (обычно используют программу genpowerd).
Если питание пропадет, то UPS сообщит об этом программе, а та в свою очередь передаст информацию init, который обработает действие powerfail. Если питание восстановится, будет обработано действие powerokwait.
Программа genpowerfail — это обыкновенный скрипт. Если его запустить с параметром start, то будет запущена программа shutdown. В зависимости от состояния UPS, процедура остановки системы будет произведена сразу или с задержкой на одну или две минуты. Если скрипт запустить с параметром stop, то процедура остановки системы будет отменена (shutdown -c).
После выполнения программ rc.S и rc.M, init запускает программу agetty. В других дистрибутивах может быть другая версия программы. Например, в SuSE Linux используется mingetty. Задача программы — инициализировать консоль на последовательном устройстве. В нашем случае, инициализируются консоли на виртуальных терминалах с 1-го по 6-й.
Обратите внимание на то, что в Slackware Liniux, на 4-м уровне выполнения (графический вход в систему) консоль инициализируется только на 6-м виртуальном терминале.
Согласно действия respawn, init запускает программу и не ожидая ее завершения выполняет следующие строки. Но он не забывает о запущенных программах, он за ними следит. Если программа завершит свою работу — init запускает ее снова. Именно поэтому, после выхода из системы на экране терминала появляется приглашение входа в систему.
Эта строка будет выполняться только на 4-м уровне выполнения.
Уровни инициализации
В процессе загрузки, после инициализации ядра, ядро запускает /sbin/init как первый процесс пользовательского режима. init отвечает за дальнейшую загрузку системы. Для этого он запускает так называемые стартовые скрипты, которые выполняют проверку и монтирование файловых систем, запуск необходимых демонов, настройку ядра (в том числе загрузку модулей ядра согласно установленному оборудованию, настройку IP-адресов, таблиц маршрутизации и др.), запуск графической оболочки и другие действия.
В операционных системах Unix/Linux с помощью init можно изменить уровень инициализации. Уровень инициализации — степень загрузки операционной системы. Вот как происходит инициализация системы: процесс init запускается и анализирует файл /etc/inittab. Следует отметить, что приведенная здесь система инициализации работает на системах Linux и Unix System V и она несколько отличается от стиля инициализации системы в BSD-подобных системах.
По умолчанию, в системе использовано 7 уровней инициализации:
0 - остановка системы
1 - загрузка в однопользовательском режиме
2 - загрузка в многопользовательском режиме без поддержки сети
3 - загрузка в многопользовательском режиме с поддержкой сети
4 - не используется
5 - загрузка в многопользовательском режиме с поддержкой сети и графического входа в систему
6 - перезагрузкаНабрав init n в терминале (с правами суперпользователя), где n — номер уровня инициализации, можно переключиться в любой из вышеперечисленных уровней.
Стартовые скрипты для каждого уровня находятся в каталогах с /etc/rc0.d до /etc/rc6.d, где цифра после rc соответствует номеру уровня инициализации.
Альтернативы init
Сейчас существует множество систем, призванных заменить собой классический init: Upstart, Runit, Daemontools, Launchd, Initng, systemd. Все они разрабатывались изначально для определенных дистрибутивов Linux или вообще для других систем.
В этой статье я попробую рассмотреть безопасность чуть-чуть повыше ядра, а именно: как работает безопасность в Native user space. Мы коснемся темы процесса загрузки операционной системы и рассмотрим структуру файловой системы Android. Как я уже говорил, я не очень силен в Linux, поэтому если заметите неточности, то исправляйте — меня научите и статью улучшите. Так как эта тема довольно обширная, я решил разбить её на две части. В первой части мы рассмотрим процесс загрузки операционной системы и особенности файловой системы. Всем кому интересно, добро пожаловать!
Список статей
Что подразумевается под Native user space
Под Native user space подразумеваются все компоненты пространства пользователя, которые выполняются вне Dalvik Virtual Machine, и которые не являются частью Linux kernel.
Уровни выполнения
В Linux существует такое понятие как уровень выполнения (run level). Уровень выполнения обозначается числами от 0 до 6.
Система в определенный момент времени находится на соответствующем уровне выполнения. Вы, как администратор системы можете переводить ее с одного уровня выполнения на другой. Это делается при помощи программы init (или telinit). Для этого программе в качестве аргумента передается число соответствующее уровню выполнения. Например, что бы перевести систему на 3-й уровень выполнения, необходимо запустить init следующим образом:
В различных дистрибутивах Linux уровни выполнения используются для различных целей.
Современная версия программы init может использовать десять уровней выполнения, но обычно используются только семь.
1 — однопользовательский режим (single user mode). Предназначен для различных административных действий по восстановлению системы. По своему смыслу аналогичен Safe Mode Windows, но полностью его не повторяет. На этом уровне выполнения система полностью сконфигурирована, но не запущен ни один сервис, а из пользователей может работать только один root.
2 — не используется, но сконфигурирован как уровень выполнения 3. В RedHat и SuSE Linux, сконфигурирован, как уровень выполнения 3, но без поддержки сетевых файловых систем. В Debian используется как многопользовательский режим.
4 — В Slackware Linux используется для графического входа в систему. В RedHat и SuSE Linux не сконфигурирован.
5 — В RedHat и SuSE Linux используется для графического входа в систему. В Slackware Linux не сконфигурирован.
Суперпользователь может остановить систему, переведя её на нулевой уровень:
Или перегрузить систему:
Содержание
Процесс загрузки Android
Давайте рассмотрим несколько шагов процесса загрузки операционной системы Android. Эта картинка взята из книги «Embedded Android», там же можно найти и более детальное описание. Хотя в целом я и понимаю процесс, но для меня это больше магия :)
CPU. Когда вы нажимаете на кнопку включения, на процессор вашего устройства начинает подаваться напряжение. Так как до этого момента процессор был выключен, и так как он не способен сохранять свое состояние без подачи напряжения, то сразу после старта он находится в некотором неинициализированном состоянии. В данном случае процессор считывает из своего специального регистра некоторый жестко зашитый адрес и начинает выполнять инструкции начиная с него. Чаще всего, этот адрес указывает на чип, в который зашит bootloader (загрузчик).
Bootloader. Bootloader инициализирует RAM и загружает в неё Linux kernel. Кроме того Bootloader создает RAMdisk.
Linux kernel. Ядро инициализирует различные подсистемы, встроенные драйвера и монтирует root filesystem (корневую файловую систему). После этого ядро может запускать первую программу.
На этом магия заканчивается и дальше всё становится более-менее понятно.Первой программой в случае Android является init. Исполняемый файл находится в корневой директории (/init). Именно эту программу стартует ядро после своей загрузки. Её исходники находятся в папке system/core/init/ Давайте в них слегка покопаемся. Нас интересует system/core/init/init.c:
Вначале мы создаем и монтируем некоторые необходимые для работы директории, а потом парсим файл /init.rc и выполняем то, что распарсили. Формат /init.rc файла очень хорошо описан в readme, там же можно найти и пример. Если кратко, то этот файл представляет собой набор actions (секций — именнованная последовательность комманд). Каждая последовательность команд срабатывает по определенному trigger (триггеру). Например, следующая последовательно — это action, в которой trigger — это fs, а последовательность команд — это набор mount команд:
Исходный файл /init.rc находится в system/core/rootdir/init.rc Давайте рассмотрим некоторые основные его части, хотя я вам очень советую просмотреть его полность. После этого многие вещи вам должны стать понятны. Итак, начинается наш файл следующими строками:
После этого происходит инициализация переменных, необходимых для работы устройства. Если вас заинтересует эта тема, то вы легко найдете информацию о той или иной комманде. Давайте подробно рассмотрим следующий блок (который я уже приводил в этой статье):
MTD — Memory Technology Devices. Если в общих чертах, то MTD — это специальный чип с энергонезависимой (т.е. данные на этом чипе сохраняются после перезагрузки или выключения) flash-памятью (типа NOR или NAND), на который сохраняются образы дисков. В этой статье более подробно рассказывается об этом типе устройств, а также об ограничениях. Специально для этих разновидностей flash-памяти были разработаны специальные файловые системы, например, YAFFS. Одно из самых важных ограничений этих типов памяти заключается в том, что для того чтобы записать данные в сектор, куда уже записаны какие-то данные, вам надо полностью сначала стереть весь сектор. Поэтому производители стали переходить на новый тип блочной flash-памяти (eMMC), на которые можно поставить обычную ext4 файловую систему и избавиться от указанного ограничения. Т.к. я показываю пример init.rc файла для эмулятора, где вся работа эмулируется, то в нем по умолчанию используется файловая система YAFFS2 (думаю, что это пережитки прошлого, т.к. YAFFS2 использовалась для всех устройств до Android 2.2). В реальном устройстве (это как раз один из примеров, когда необходимо использовать init.rc файл для определенного железа) эти комманды будут перезаписаны. Например, в случае устройства herring (Google Nexus S), в файле init.herring.rc эта секция выглядит следующим образом:
Где fstab.herring — это файл, содержимое которого выглядит следующим образом:
Как вы могли заметить, /system, /data, /cache — это просто mounting points (точки монтирования файловой системы), которые указывают либо на MTD устройства (в случае эмулятора), либо на блочные устройства (в случае настоящего устройства), куда записаны соответствующие дисковые образы (system.img, userdata.img и cache.img). Я не уверен, но думаю, что внутри смартфона находится один единственный чип с flash-памятью, разделенный на partitions (тома), в каждый из которых записан соответствующий образ. Этот чип с flash-памятью — то, что мы знаем под именем Internal storage (внутренняя память), объем которой — один из основных параметров смартфона.Следует заметить, что /system смонтирован read-only (только для чтения). Это означает, что содержимое данного раздела не изменяется в процессе работы устройства, а только когда вы, например, обновляете систему на вашем устройстве (используя системные обновления).
Продолжим рассматривать наш init.rc. По триггеру post-fs-data формируется базовая структура файловой системы /data раздела. Там, в общем всё понятно — набор mkdir, chown, chmod команд.
Далее init.rc запускает несколько демонов. Если вернуться к рисунку в начале статьи, то они перечислены в блоке Native daemons. На этом мы пока остановимся. Как вы могли заметить из рисунка, я не полностью рассмотрел процесс загрузки операционной системы. Некоторые непокрытые этапы я рассмотрю в следующих статья.
Читайте также: