Каковы минимальные приложения корневой файловой системы, которые требуются для полной загрузки Linux?


17

Это вопрос о приложениях пользовательского пространства, но выслушайте меня!

Для загрузки функционального дистрибутива Linux необходимы, так сказать, три «приложения»:

  1. Bootloader - для встраиваемых систем обычно это U-Boot, хотя это и не является жестким требованием

  2. Ядро - это довольно просто.

  3. Корневая файловая система - без нее загрузка невозможна. Содержит файловую систему, в которую загружается ядро, и где initона называется form.

Мой вопрос касается № 3. Если кто-то хотел создать крайне минимальный rootfs (для этого вопроса, скажем, без графического интерфейса, только оболочка), какие файлы / программы требуются для загрузки в оболочку?


Определите минимальное. Вы можете использовать только один исполняемый файл и ничего другого, как описано на сайте: superuser.com/a/991733/128124 Просто потому, что он не может каждый выход или панику, поэтому вам нужен бесконечный цикл или длительный сон. Аналогичный вопрос: unix.stackexchange.com/questions/17122/…
Сиро Сантилли 事件 改造 中心 法轮功 六四 事件

Ответы:


32

Это полностью зависит от того, какие услуги вы хотите иметь на своем устройстве.

программы

Вы можете заставить Linux загружаться прямо в оболочку . Это не очень полезно в производстве - кому бы просто хотелось, чтобы там была оболочка - но это полезно в качестве механизма вмешательства, когда у вас есть интерактивный загрузчик: переход init=/bin/shк командной строке ядра. Все системы Linux (и все системы Unix) имеют оболочку в стиле Bourne / POSIX /bin/sh.

Вам понадобится набор утилит оболочки . BusyBox - очень распространенный выбор; она содержит оболочку и общие утилиты для файла и обработки текста ( cp, grep, ...), сетевые настройки ( ping, ifconfig, ...), манипуляции с процессом ( ps, nice, ...), а также различные другие инструменты системы ( fdisk, mount, syslogd...). BusyBox является чрезвычайно настраиваемым: вы можете выбрать, какие инструменты вы хотите, и даже отдельные функции во время компиляции, чтобы получить правильный размер / компромисс функциональности для вашего приложения. Помимо sh, голый минимум , который вы не можете сделать ничего не есть mount, umountи halt, но было бы нетипичной не имеют также cat, cp, mv, rm,mkdir, rmdir, ps, syncИ еще несколько. BusyBox устанавливается как один двоичный файл busyboxс символической ссылкой для каждой утилиты.

Первый процесс в нормальной системе Unix называется init. Его работа - запускать другие сервисы. BusyBox содержит систему инициализации. В дополнение к initдвоичному /sbinфайлу (обычно расположенному в ) вам понадобятся его конфигурационные файлы (обычно называемые /etc/inittab- некоторые современные замены init покончили с этим файлом, но вы не найдете их в небольшой встроенной системе), которые указывают, какие службы нужно запускать и когда. Для BusyBox /etc/inittabнеобязательно; если он отсутствует, вы получаете корневую оболочку на консоли и скрипт /etc/init.d/rcS(расположение по умолчанию) выполняется во время загрузки.

Это все, что вам нужно, кроме программ, которые заставляют ваше устройство делать что-то полезное. Например, на моем домашнем маршрутизаторе, использующем вариант OpenWrt , единственными программами являются BusyBox nvram(для чтения и изменения настроек в NVRAM) и сетевые утилиты.

Если все ваши исполняемые файлы статически не связаны, вам потребуется динамический загрузчик ( ld.soкоторый может вызываться разными именами в зависимости от выбора libc и архитектуры процессора) и все динамические библиотеки ( /lib/lib*.soвозможно, некоторые из них /usr/lib), необходимые для эти исполняемые файлы.

Структура каталогов

Filesystem Hierarchy Standard описывает общую структуру каталогов системы Linux. Он ориентирован на установку на настольных компьютерах и серверах: многие из них могут быть опущены во встроенной системе. Вот типичный минимум.

  • /bin: исполняемые программы (некоторые могут быть /usr/binвместо).
  • /dev: узлы устройства (см. ниже)
  • /etc: файлы конфигурации
  • /lib: общие библиотеки, включая динамический загрузчик (если все исполняемые файлы статически не связаны)
  • /proc: точка монтирования для файловой системы proc
  • /sbin: исполняемые программы. Различие с тем /bin, что /sbinэто для программ, которые полезны только для системного администратора, но это различие не имеет смысла на встроенных устройствах. Вы можете сделать /sbinсимволическую ссылку на /bin.
  • /mnt: удобно иметь в корневых файловых системах только для чтения в качестве точки монтирования во время обслуживания
  • /sys: точка монтирования для файловой системы sysfs
  • /tmp: расположение для временных файлов (часто tmpfsмонтирование)
  • /usr: Содержит подкаталоги bin, libи sbin. /usrсуществует для дополнительных файлов, которые не находятся в корневой файловой системе. Если у вас его нет, вы можете сделать /usrсимволическую ссылку на корневой каталог.

Файлы устройства

Вот несколько типичных записей в минимуме /dev:

  • console
  • full (запись в него всегда сообщает «на устройстве не осталось места»)
  • log(сокет, который программы используют для отправки записей журнала), если у вас есть syslogdдемон (например, BusyBox), читающий из него
  • null (действует как файл, который всегда пуст)
  • ptmxи ptsкаталог , если вы хотите использовать псевдо-терминалы (то есть любой терминал, отличный от консоли) - например, если устройство подключено к сети, и вы хотите подключиться через telnet или ssh
  • random (возвращает случайные байты, блокирует риски)
  • tty (всегда обозначает терминал программы)
  • urandom (возвращает случайные байты, никогда не блокирует, но может быть неслучайным на недавно загруженном устройстве)
  • zero (содержит бесконечную последовательность нулевых байтов)

Помимо этого вам понадобятся записи для вашего оборудования (кроме сетевых интерфейсов, в которые они не попадают /dev): последовательные порты, хранилище и т. Д.

Для встроенных устройств вы обычно создаете записи устройства непосредственно в корневой файловой системе. В высокопроизводительных системах есть сценарий, который вызывается MAKEDEVдля создания /devзаписей, но во встроенной системе этот сценарий часто не входит в образ. Если какое-либо оборудование может быть подключено в горячем режиме (например, если устройство имеет хост-порт USB), тогда им /devдолжно управлять udev (у вас может быть минимальный набор в корневой файловой системе).

Действия при загрузке

Помимо корневой файловой системы, вам нужно смонтировать еще несколько для нормальной работы:

  • procfs on /proc(в значительной степени незаменимый)
  • sysfs on /sys(в значительной степени незаменимый)
  • tmpfsфайловая система включена /tmp(чтобы позволить программам создавать временные файлы, которые будут в ОЗУ, а не в корневой файловой системе, которая может быть во флэш-памяти или только для чтения)
  • tmpfs, devfs или devtmpfs включены, /devесли они динамические (см. udev в разделе «Файлы устройств» выше)
  • devpts on, /dev/ptsесли вы хотите использовать [псевдо-терминалы (см. замечание ptsвыше)

Вы можете сделать /etc/fstabфайл и позвонить mount -a, или запустить mountвручную.

Запустите демон syslog (а также klogdдля журналов ядра, если syslogdпрограмма об этом не позаботится), если у вас есть место для записи журналов.

После этого устройство готово к запуску специфичных для приложения сервисов.

Как сделать корневую файловую систему

Это длинная и разнообразная история, поэтому все, что я здесь сделаю, - это несколько советов.

Корневая файловая система может храниться в ОЗУ (загружаться из (обычно сжатого) образа в ПЗУ или флэш-памяти) или в файловой системе на диске (храниться в ПЗУ или во флэш-памяти) или загружаться из сети (часто через TFTP ), если применимо , Если корневая файловая система находится в ОЗУ, сделайте ее initramfs - файловой системой ОЗУ, содержимое которой создается во время загрузки.

Существует множество платформ для сборки корневых образов для встроенных систем. В FAQ BusyBox есть несколько указателей . Buildroot является популярным, позволяя вам создать целый корневой образ с настройкой, аналогичной ядру Linux и BusyBox. OpenEmbedded - еще один такой фреймворк.

В Википедии есть (неполный) список популярных дистрибутивов встроенного Linux . Примером встроенного Linux, который вы можете иметь рядом с вами, является семейство операционных систем OpenWrt для сетевых устройств (популярное на домашних маршрутизаторах тинкеров). Если вы хотите учиться на собственном опыте, вы можете попробовать Linux с нуля , но он ориентирован на настольных систем для любителей, а не на встраиваемые устройства.

Примечание по Linux против ядра Linux

Единственное поведение, которое запекается в ядре Linux, заключается в том, что первая программа запускается во время загрузки. (Я не буду вдаваться в тонкости initrd и initramfs .) Эта программа, традиционно называемая init , имеет идентификатор процесса 1 и имеет определенные привилегии (невосприимчивость к сигналам KILL ) и обязанности (пожинает сирот ). Вы можете запустить систему с ядром Linux и запустить все, что захотите, в качестве первого процесса, но тогда у вас будет операционная система, основанная на ядре Linux, а не то, что обычно называется «Linux» -  Linux , в обычном смысле слова термина, Unix- подобная операционная система, ядро ​​которой является ядром Linux, Например, Android - это операционная система, которая не похожа на Unix, но основана на ядре Linux.


Отличный ответ. Я упомянул загрузку в Linux только в заголовке b / c, который, скорее всего, будет искать, настолько отличное дополнение о Linux против Linux Kernel, что требует более широкого распространения знаний.
MDMoore313

@ BigHomie Помните, Фонд свободного программного обеспечения хочет, чтобы мы все назвали его GNU / Linux, поскольку на большинстве (всех?) «Linux distros» программное обеспечение - это GNU, хотя ядром является Linux (отсюда и GNU / Linux).
BenjiWiebe

Мех, ни у кого нет времени на это. Тогда мой дистрибутив должен называться Busybox / Linux ?? Я знаю, я знаю, это не вы его Stallworth, просто вентиляция;)
MDMoore313

1
@BenjiWiebe Или GNU / X11 / Apache / Linux / TeX / Perl / Python / FreeCiv . Кроме RMS, все называют это «Linux».
Жиль "ТАК ... перестать быть злым"

@ Жиль Ну, кроме Debian, наверное. :)
CVn

5

Все, что вам нужно, это один статически связанный исполняемый файл, размещенный в файловой системе изолированно. Вам не нужны никакие другие файлы. Этот исполняемый файл является процессом init. Это может быть busybox. Это дает вам оболочку и множество других утилит, все само по себе. Вы можете перейти к полностью работающей системе, просто выполнив команды вручную в busybox, чтобы смонтировать корневую файловую систему для чтения-записи, создания узлов / dev, exec real init и т. Д.


Да, я знал, что busybox придет. Посмотрим, появится ли что-нибудь еще.
MDMoore313

4

Если вам не нужны никакие утилиты оболочки, mkshподойдет статически связанный двоичный файл (например, для klibc - 130K в Linux / i386). Вам нужен сценарий /linuxrcor /initили, /sbin/initкоторый просто вызывает mksh -l -T!/dev/tty1цикл:

#!/bin/mksh
while true; do
    /bin/mksh -l -T!/dev/tty1
done

Эта -T!$ttyопция является недавним дополнением, mkshкоторое говорит ей, чтобы она вызывала новую оболочку на данном терминале и ждала его. (До этого был только -T-в dæmonise программка и -T$ttyна икру на терминал , но не ждать. Это было не так красиво) . В -lопции просто говорит ему , чтобы запустить оболочку входа в систему (которая читает /etc/profile, ~/.profileа ~/.mkshrc).

Это предполагает, что ваш терминал является /dev/tty1заменой. (С большей магией, терминал может быть автоматически обнаружен. /dev/consoleНе даст вам полный контроль над работой.)

Вам нужно несколько файлов /devдля этого:

  • / DEV / консоли
  • / DEV / нуль
  • / DEV / TTY
  • / DEV / tty1

Загрузка с опцией ядра devtmpfs.mount=1устраняет необходимость в заполненном /dev, просто пусть это будет пустой каталог (подходящий для использования в качестве точки монтирования).

Вы обычно захотите иметь некоторые утилиты (из klibc, busybox, beastiebox, toybox или toolbox), но они на самом деле не нужны.

Возможно, вы захотите добавить ~/.mkshrcфайл, который устанавливает $ PS1 и некоторые базовые псевдонимы и функции оболочки.

Однажды я сделал initrd сжатый 171K (371K несжатый) для Linux / m68k, используя только mksh (и его пример файла mkshrc) и klibc-utils. (Это было до того, как -T! Был добавлен в оболочку, однако, /dev/tty2вместо этого он вызвал оболочку входа в систему и вывел на консоль сообщение, сообщающее пользователю о необходимости переключения терминалов.) Он работает нормально.

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

Отказ от ответственности: я разработчик MKSH.


Это отличный ответ, спасибо за обмен, а также спасибо за mksh.
JoshuaRLi

2

Минимальная начальная программа Hello World, шаг за шагом

введите описание изображения здесь

Скомпилируйте привет мир без каких-либо зависимостей, который заканчивается бесконечным циклом. init.S:

.global _start
_start:
    mov $1, %rax
    mov $1, %rdi
    mov $message, %rsi
    mov $message_len, %rdx
    syscall
    jmp .
    message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
    .equ message_len, . - message

Мы не можем использовать sys_exit, иначе ядро ​​паникует.

Потом:

mkdir d
as --64 -o init.o init.S
ld -o init d/init.o
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"

Это создает файловую систему с нашим hello world at /init, которая является первой пользовательской программой, которую будет запускать ядро. Мы могли бы также добавить больше файлов, d/и они были бы доступны из /initпрограммы при запуске ядра.

Затем cdв дерево ядра Linux, сборка, как обычно, и запустить его в QEMU:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"

И вы должны увидеть строку:

FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR

на экране эмулятора! Обратите внимание, что это не последняя строка, поэтому вам нужно посмотреть немного дальше.

Вы также можете использовать программы на C, если статически связываете их:

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

int main() {
    printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
    sleep(0xFFFFFFFF);
    return 0;
}

с:

gcc -static init.c -o init

Вы можете работать на реальном оборудовании с включенным USB /dev/sdXи:

make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX

Отличный источник на эту тему: http://landley.net/writing/rootfs-howto.html Также объясняется, как использоватьgen_initramfs_list.sh , это скрипт из дерева исходных текстов ядра Linux, помогающий автоматизировать процесс.

Следующий шаг: настройте BusyBox, чтобы вы могли взаимодействовать с системой: https://github.com/cirosantilli/runlinux

Протестировано на Ubuntu 16.10, QEMU 2.6.1.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.