完全引导linux所需的最小根文件系统应用程序是什么?


17

这是有关用户空间应用程序的问题,但是请听我说!

可以说,启动Linux的功能发行版需要三个“应用程序”:

  1. Bootloader-对于嵌入式设备,通常不是U-Boot,虽然不是硬性要求。

  2. 内核-非常简单。

  3. 根文件系统-没有它就无法启动到外壳。包含内核引导至的文件系统,并在其中init称为表格。

我的问题是关于#3的。如果有人想构建一个极小的rootfs(对于这个问题,可以说没有GUI,仅shell),那么引导到shell需要什么文件/程序?


定义最小值。您可以只使用一个可执行文件,而没有其他说明,请参见superuser.com/a/991733/128124只是它不能每次退出或出现恐慌,所以您需要无限循环或长时间睡眠。类似的问题:unix.stackexchange.com/questions/17122/...
西罗桑蒂利新疆改造中心法轮功六四事件

Answers:


32

这完全取决于您想要在设备上提供哪些服务。

程式

您可以使Linux直接引导到shell中。它在生产环境中不是很有用-只是想让外壳坐在那里-但是当您有交互式引导程序时,它作为干预机制很有用:传递init=/bin/sh给内核命令行。所有Linux系统(和所有unix系统)在中都有Bourne / POSIX风格的shell /bin/sh

您将需要一组Shell实用程序BusyBox是一个非常常见的选择。它包含文件和文本处理(外壳和共同事业cpgrep...),网络设置(pingifconfig,...),工艺操作(psnice,...),以及其他各种系统工具(fdiskmountsyslogd,...)。BusyBox具有极高的可配置性:您可以在编译时选择所需的工具,甚至可以选择各个功能,以获得适合您的应用程序的正确尺寸/功能。除此之外sh,最起码,你真的不能做任何事情,而不是mountumounthalt,但它是非典型的不也有catcpmvrmmkdirrmdirpssync和几个。BusyBox作为一个名为的二进制文件安装busybox,每个实用程序都有一个符号链接。

在普通的UNIX系统上,第一个过程称为init。它的工作是启动其他服务。BusyBox包含一个初始化系统。除了init二进制文件(通常位于中/sbin)之外,您还需要其配置文件(通常称为/etc/inittab-一些现代的init替代品会删除该文件,但在小型嵌入式系统上找不到它们),这些文件会指示要启动的服务什么时候。对于BusyBox,/etc/inittab是可选的;如果缺少它,您将在控制台上获得一个根shell,并且脚本/etc/init.d/rcS(默认位置)在引导时执行。

这就是您所需要的,当然除了使您的设备执行有用的程序之外。例如,在运行OpenWrt变体的家用路由器上,仅有的程序是BusyBox nvram(用于读取和更改NVRAM中的设置)和网络实用程序。

除非所有的可执行文件的静态链接,你将需要动态加载器(ld.so,它可以根据所上的处理器架构的libc而选择不同的名称来称呼)和所有的动态库/lib/lib*.so,也许这些中/usr/lib)所要求的这些可执行文件。

目录结构

文件系统层次标准描述了Linux系统的公共目录结构。它适用于台式机和服务器安装:在嵌入式系统上可以忽略很多。这是典型的最小值。

  • /bin:可执行程序(有些可能在其中/usr/bin)。
  • /dev:设备节点(请参见下文)
  • /etc:配置文件
  • /lib:共享库,包括动态加载程序(除非所有可执行文件都是静态链接的)
  • /procproc文件系统的安装点
  • /sbin:可执行程序。有区别/bin的是,/sbin对于那些只对系统管理员有用的程序,但这种区别并不在嵌入式设备上有意义的。您可以/sbin建立的符号链接/bin
  • /mnt:在维护期间方便将只读根文件系统作为临时挂载点使用
  • /syssysfs文件系统的安装点
  • /tmp:临时文件的位置(通常是tmpfs挂载)
  • /usr:包含子目录binlibsbin/usr存在于不在根文件系统上的其他文件。如果没有,您可以/usr建立指向根目录的符号链接。

设备文件

以下是一些最低限度的典型条目/dev

  • console
  • full (向其写入始终报告“设备上没有剩余空间”)
  • log(程序用来发送日志条目的套接字),如果您有syslogd守护进程(例如BusyBox的)正在从中读取
  • null (就像一个始终为空的文件)
  • ptmxpts目录,如果您想使用伪终端(即控制台以外的任何终端),例如,如果设备已联网并且想要通过telnet或ssh登录
  • random (返回随机字节,有阻塞的危险)
  • tty (总是指定程序的终端)
  • urandom (返回随机字节,从不阻塞,但在新启动的设备上可能是非随机的)
  • zero (包含无限个空字节序列)

除此之外,您还需要硬件的条目(网络接口除外,这些条目不会在中获得条目/dev):串行端口,存储设备等。

对于嵌入式设备,通常可以直接在根文件系统上创建设备条目。高端系统具有一个MAKEDEV用于创建/dev条目的脚本,但是在嵌入式系统上,该脚本通常不捆绑到映像中。如果可以热插拔某些硬件(例如,如果设备具有USB主机端口),/dev则应由udev管理(您在根文件系统上可能仍具有最小设置)。

引导时间动作

除了根文件系统,您还需要安装一些其他文件才能正常运行:

  • PROCFS/proc(几乎必不可少)
  • sysfs/sys(几乎必不可少)
  • tmpfs上的文件系统/tmp(以允许程序创建将在RAM中而不是在闪存或只读中的根文件系统上的临时文件)
  • tmpfs,devfs或devtmpfs(/dev如果是动态的)(请参见上面“设备文件”中的udev)
  • devpts/dev/pts,如果你想使用[伪终端(请参阅有关此言pts以上)

您可以制作/etc/fstab文件并调用mount -a,也可以mount手动运行。

如果您有写日志的地方,请启动syslog守护程序(以及klogd内核日志,如果syslogd程序不处理的话)。

此后,设备准备启动特定于应用程序的服务。

如何制作根文件系统

这是一个漫长而多样的故事,所以我在这里要做的只是提供一些指导。

根文件系统可以保存在RAM中(从ROM或Flash中的(通常是压缩的)映像加载),或在基于磁盘的文件系统中(存储在ROM或Flash中),或者从网络(通常通过TFTP)加载。。如果根文件系统位于RAM中,则将其设置为initramfs —一种RAM文件系统,其内容在引导时创建。

存在许多用于为嵌入式系统组装根映像的框架。在BusyBox FAQ中有一些指示。Buildroot是一种流行的方法,它允许您使用类似于Linux内核和BusyBox的设置来构建整个根映像。OpenEmbedded是另一个这样的框架。

Wikipedia有一个(不完整的)流行的嵌入式Linux发行列表。您可能会遇到的嵌入式Linux的一个示例是用于网络设备的OpenWrt操作系统家族(在修补匠的家庭路由器上很受欢迎)。如果您想从经验中学习,可以尝试Scratch的Linux,但这是针对爱好者的台式机系统,而不是嵌入式设备。

关于Linux vs Linux内核的说明

植入Linux内核的唯一行为是在引导时启动的第一个程序。(我不会在这里讨论initrdinitramfs的细节。)该程序传统上称为init,具有进程ID 1,并且具有某些特权(对KILL信号具有免疫性)和职责(对孤儿有收割)。您可以运行在Linux内核的系统,并开始任何你想要作为第一个过程,但你拥有的是基于Linux内核的操作系统,而不是通常所谓的“Linux” -  Linux的,在常识这个术语是类似于Unix的操作系统,其内核是Linux内核。例如,Android是一个不像Unix的操作系统,但是基于Linux内核。


极好的答案。我只在标题b / c中提到了引导进入 Linux,这很可能会被搜索到,所以关于Linux vs Linux Kernel的大量补充,需要更广泛的知识。
MDMoore313

@BigHomie记住,自由软件基金会希望我们所有人都将其称为GNU / Linux,因为在大多数(全部?)“ Linux发行版”中,该软件是GNU,即使内核是Linux(因此也是GNU / Linux)。
BenjiWiebe 2014年

嗯,不是没有人有时间。然后我的发行版应该叫做Busybox / Linux?我知道我知道,不是你的Stallworth,只是发泄了;)
MDMoore313 2014年

1
@BenjiWiebe或GNU / X11 / Apache / Linux / TeX / Perl / Python / FreeCiv。除了RMS,每个人都将其称为“ Linux”。
吉尔斯(Gilles)'所以

@Gilles好吧,我猜除了Debian。:)
CVn 2014年

5

您所需要的只是一个静态链接的可执行文件,该文件独立存在于文件系统中。您不需要任何其他文件。该可执行文件是初始化过程。它可以是busybox。这样就给您提供了一个Shell和许多其他实用程序,全部就在其中。您可以通过在busybox中手动执行命令以挂载读写的根文件系统,创建/ dev节点,exec real init等方式进入功能全面的系统。


是的,我知道busybox即将来临。让我们看看是否还有其他东西出现。
MDMoore313

4

如果不需要任何shell实用程序,则可以使用静态链接的mksh二进制文件(例如,针对klibc –在Linux / i386上为130K)。您需要只在循环中调用的/linuxrcor /init/sbin/init脚本mksh -l -T!/dev/tty1

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

-T!$tty选项是mksh对它的最新添加,它告诉它在给定的终端上生成一个新的shell并等待它。(在此之前,只有-T-到dæmonise一个PROGRAMM和-T$tty产卵终端上而不是等待它。这不是那么好。)的-l选项只是告诉它来运行一个登录shell(读取/etc/profile~/.profile~/.mkshrc)。

假设您的终端为/dev/tty1,替代。(有了更多的魔力,可以自动找到终端。/dev/console将无法完全控制工作。)

您需要一些文件/dev才能起作用:

  • / dev /控制台
  • / dev /空
  • / dev / tty
  • / dev / tty1

使用kernel选项引导devtmpfs.mount=1无需再填充目录/dev,只需将其设为空目录(适合用作挂载点)即可。

通常,您将需要一些实用程序(来自klibc,busybox,beastiebox,toybox或Toolbox),但实际上并不需要它们。

您可能想要添加一个~/.mkshrc文件,该文件设置$ PS1以及一些基本的shell别名和功能。

我曾经仅使用mksh(及其示例mkshrc文件)和klibc-utils为Linux / m68k制作了171K压缩(371K未压缩)initrd。(不过,这是在将-T!添加到shell之前的,因此它/dev/tty2改为生成了登录shell ,并向控制台回显了一条消息,告诉用户切换终端。)它可以正常工作。

这是一个真正的最低设置。其他答案为功能更强大的系统提供了极好的建议。这是真正的特殊情况。

免责声明:我是mksh开发人员。


这是一个很好的答案,感谢您的分享,也感谢mksh
JoshuaRLi

2

最小的init hello world程序逐步

在此处输入图片说明

编译一个没有任何以无限循环结尾的依赖项的hello世界。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"

这会创建一个文件系统,其问候世界位于/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上测试。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.