Как стартует User space в Linux?

Ответ

Запуск пользовательского пространства (user space) — это заключительный этап загрузки ядра Linux. Процесс выглядит так:

  1. Инициализация ядра: Ядро монтирует корневую файловую систему (rootfs), инициализирует устройства и подсистемы.
  2. Запуск init-процесса (PID 1): Ядро выполняет системный вызов execve() для запуска программы, указанной в параметре ядра init=. По умолчанию это /sbin/init, который сегодня обычно является симлинком на systemd.
  3. Инициализация системы systemd:
    • Монтирует файловые системы из /etc/fstab.
    • Запускает системные сервисы (демоны), описанные в юнитах (.service, .socket и т.д.).
    • Активирует sysinit.target и basic.target.
  4. Запуск входа в систему: Systemd запускает getty@.service для виртуальных консолей (tty1-tty6) или display-manager.service для графического входа.
  5. Аутентификация: Getty или дисплей-менеджер запускают login или графический экран входа для аутентификации пользователя.
  6. Пользовательская сессия: После успешного входа запускается оболочка пользователя (например, bash) или сессия рабочего стола.

Минимальный пример на C: Можно написать примитивный init, который просто запускает оболочку (это демонстрирует принцип, но не используется в реальных системах).

#include <unistd.h>

int main() {
    // exec заменит текущий процесс (PID 1) на /bin/sh
    execl("/bin/sh", "sh", NULL);
    // Если execl вернёт управление, значит произошла ошибка
    return 1;
}

Ответ 18+ 🔞

А, ну вот, наконец-то добрались до самого интересного — как эта железяка оживает и начинает нам служить! Сидишь ты, значит, с утра, кофе пьёшь, а комп уже там внутри вовсю пиздец какую магию творит. Так вот, запуск пользовательского пространства — это, по сути, тот самый момент, когда ядро, наконец, говорит: «Ёпта, я тут всё настроил, а теперь пусть эти пользователи сами разбираются со своими косяками».

Представь: ядро — это как суровый прораб на стройке. Сначала он всё сам монтирует, провода подключает, фундамент заливает — это инициализация. Потом он смотрит на часы, вздыхает и кричит: «Эй, /sbin/init, выходи, пора работать!». А это, по сути, первый рабочий, которого он нанимает. Раньше там всякие sysvinit бегали, а сейчас почти везде этот systemd — такой менеджер-активист, который всех строит в шеренгу и заставляет работать по расписанию. Ему доверия, блядь, ноль, потому что он слишком умный и везде лезет, но деваться некуда.

И вот этот systemd начинает свою движуху. Сначала он, как хороший хозяйственник, смотрит в список дел — /etc/fstab — и монтирует все диски, которые там прописаны. Потом начинает запускать сервисы, один за другим. Это как будто он включает свет, запускает котельную, поднимает сеть. Всё это он делает, активируя какие-то там target'ы — sysinit.target, basic.target. Звучит сложно, но на деле это просто этапы: сначала самое необходимое, потом всё остальное.

Дальше самое весёлое — вход в систему. Если ты сидишь за консолью без графики, то systemd запускает на твоих tty1-tty6 этих самых getty. Это такие маленькие програмки-привратники, которые просто показывают надпись login: и ждут, когда ты введёшь своё имя. А если у тебя графическая оболочка, то вместо getty запускается целый дисплей-менеджер — это уже такой пафосный швейцар с золотыми пуговицами, который показывает красивые картинки и поля для логина с паролем.

Ты вводишь свои данные, система проверяет — не пидарас ли шерстяной? — и если всё ок, запускает твою личную сессию. То есть твой любимый bash (или zsh, если ты хипстер) или вообще целый рабочий стол с окошками и иконками. Вот с этого момента ядро уже почти не вмешивается, оно просто стоит сбоку и смотрит, как ты всё просрешь своими кривыми командами.

А теперь, чтобы ты совсем проникся, глянь на этот кусок кода. Это, блядь, самый примитивный init, какой только можно представить. Он не делает нихуя, кроме как пытается запустить оболочку. Если бы так работала реальная система, это был бы пиздец, но для понимания принципа — самое то.

#include <unistd.h>

int main() {
    // exec заменит текущий процесс (PID 1) на /bin/sh
    execl("/bin/sh", "sh", NULL);
    // Если execl вернёт управление, значит произошла ошибка
    return 1;
}

Вот и вся магия. Ядро запускает эту программу как процесс с номером 1, а она сразу же говорит: «А похуй на всё, давайте лучше bash!» и заменяет себя оболочкой. Красота, да? Прям как в жизни — начальник нанял менеджера, а тот сразу ушёл в запой.