Các ứng dụng hệ thống tập tin gốc tối thiểu được yêu cầu để khởi động đầy đủ linux là gì?


16

Đó là một câu hỏi về các ứng dụng không gian người dùng, nhưng hãy nghe tôi nói!

Ba "ứng dụng", có thể nói, được yêu cầu để khởi động một bản phân phối chức năng của Linux:

  1. Bootloader - Đối với nhúng thường là U-Boot, mặc dù không phải là một yêu cầu khó.

  2. Kernel - Điều đó khá đơn giản.

  3. Root Filesystem - Không thể khởi động vào trình bao mà không có nó. Chứa hệ thống tập tin mà kernel khởi động và nơi initđược gọi là biểu mẫu.

Câu hỏi của tôi liên quan đến # 3. Nếu ai đó muốn xây dựng một rootfs cực kỳ tối thiểu (đối với câu hỏi này, giả sử không có GUI, chỉ shell), những tập tin / chương trình nào được yêu cầu để khởi động vào shell?


Xác định tối thiểu. Bạn có thể sử dụng chỉ một thực thi duy nhất mà không có gì khác như được giải thích tại: superuser.com/a/991733/128124 Chỉ là nó không thể thoát ra hoặc hoảng loạn, vì vậy bạn cần một vòng lặp vô hạn hoặc giấc ngủ dài. Câu hỏi tương tự: unix.stackexchange.com/questions/17122/ từ
Ciro Santilli 改造

Câu trả lời:


31

Điều đó hoàn toàn phụ thuộc vào những dịch vụ bạn muốn có trên thiết bị của bạn.

Chương trình

Bạn có thể làm cho Linux khởi động trực tiếp vào một vỏ . Nó không hữu ích trong sản xuất - ai chỉ muốn có một cái vỏ ngồi ở đó - nhưng nó hữu ích như một cơ chế can thiệp khi bạn có bộ tải khởi động tương tác: chuyển init=/bin/shđến dòng lệnh kernel. Tất cả các hệ thống Linux (và tất cả các hệ thống unix) đều có vỏ kiểu Bourne / POSIX /bin/sh.

Bạn sẽ cần một bộ tiện ích vỏ . BusyBox là một lựa chọn rất phổ biến; nó chứa một vỏ và tiện ích chung cho tập tin và thao tác văn bản ( cp, grep, ...), thiết lập mạng ( ping, ifconfig, ...), quá trình thao tác ( ps, nice, ...), và các công cụ khác nhau hệ thống khác ( fdisk, mount, syslogd, ...). BusyBox có khả năng cấu hình cực cao: bạn có thể chọn công cụ nào bạn muốn và thậm chí các tính năng riêng lẻ tại thời điểm biên dịch, để có được thỏa hiệp kích thước / chức năng phù hợp cho ứng dụng của bạn. Ngoài sh, mức tối thiểu mà bạn có thể không thực sự làm bất cứ điều gì mà không là mount, umounthalt, nhưng nó sẽ là không điển hình không có cũng cat, cp, mv, rm,mkdir, rmdir, ps, syncVà một vài chi tiết. BusyBox cài đặt dưới dạng nhị phân đơn được gọi busybox, với một liên kết tượng trưng cho mỗi tiện ích.

Quá trình đầu tiên trên một hệ thống unix bình thường được gọi init. Công việc của nó là bắt đầu các dịch vụ khác. BusyBox chứa một hệ thống init. Ngoài inittệp nhị phân (thường nằm trong /sbin), bạn sẽ cần các tệp cấu hình của nó (thường được gọi là /etc/inittab- một số thay thế init hiện đại loại bỏ tệp đó nhưng bạn sẽ không tìm thấy chúng trên một hệ thống nhúng nhỏ) cho biết dịch vụ nào sẽ bắt đầu và khi. Đối với BusyBox, /etc/inittablà tùy chọn; nếu nó bị thiếu, bạn sẽ có một vỏ gốc trên bàn điều khiển và tập lệnh /etc/init.d/rcS(vị trí mặc định) được thực thi khi khởi động.

Đó là tất cả những gì bạn cần, ngoài các chương trình giúp thiết bị của bạn làm điều gì đó hữu ích. Ví dụ: trên bộ định tuyến gia đình của tôi chạy biến thể OpenWrt , các chương trình duy nhất là BusyBox, nvram(để đọc và thay đổi cài đặt trong NVRAM) và các tiện ích mạng.

Trừ khi tất cả các tệp thực thi của bạn được liên kết tĩnh, bạn sẽ cần trình tải động ( ld.socó thể được gọi bằng các tên khác nhau tùy thuộc vào lựa chọn libc và trên các kiến ​​trúc bộ xử lý) và tất cả các thư viện động ( /lib/lib*.socó lẽ một số trong số này trong /usr/lib) những thực thi này.

Cấu trúc thư mục

Các hệ thống tập tin tiêu chuẩn cấp bậc mô tả cấu trúc thư mục chung của các hệ thống Linux. Nó hướng đến việc cài đặt máy tính để bàn và máy chủ: rất nhiều trong số đó có thể được bỏ qua trên một hệ thống nhúng. Đây là một mức tối thiểu điển hình.

  • /bin: chương trình thực thi (một số có thể /usr/binthay thế).
  • /dev: các nút thiết bị (xem bên dưới)
  • /etc: tập tin cấu hình
  • /lib: các thư viện dùng chung, bao gồm trình tải động (trừ khi tất cả các tệp thực thi được liên kết tĩnh)
  • /proc: điểm gắn kết cho hệ thống tập tin Proc
  • /sbin: chương trình thực thi. Sự khác biệt với /bin/sbinlà cho các chương trình mà chỉ là hữu ích cho các quản trị hệ thống, nhưng sự khác biệt này không có ý nghĩa trên các thiết bị nhúng. Bạn có thể tạo /sbinmột liên kết tượng trưng đến /bin.
  • /mnt: tiện dụng để có trên các hệ thống tập tin gốc chỉ đọc làm điểm gắn kết trong quá trình bảo trì
  • /sys: điểm gắn kết cho hệ thống tập tin sysfs
  • /tmp: vị trí cho các tệp tạm thời (thường là một tmpfsmount)
  • /usr: Chứa các thư mục con bin, libsbin. /usrtồn tại cho các tệp bổ sung không có trên hệ thống tệp gốc. Nếu bạn không có điều đó, bạn có thể tạo /usrmột liên kết tượng trưng đến thư mục gốc.

Tập tin thiết bị

Dưới đây là một số mục tiêu biểu trong tối thiểu /dev:

  • console
  • full (viết cho nó luôn báo cáo không còn chỗ trống trên thiết bị)
  • log(một ổ cắm mà các chương trình sử dụng để gửi các mục nhật ký), nếu bạn có một syslogddaemon (chẳng hạn như BusyBox) đọc từ nó
  • null (hoạt động như một tập tin luôn trống)
  • ptmxvà một ptsthư mục , nếu bạn muốn sử dụng thiết bị đầu cuối giả (tức là bất kỳ thiết bị đầu cuối nào ngoài bảng điều khiển) - ví dụ: nếu thiết bị được nối mạng và bạn muốn telnet hoặc ssh trong
  • random (trả về byte ngẫu nhiên, chặn rủi ro)
  • tty (luôn chỉ định thiết bị đầu cuối của chương trình)
  • urandom (trả về byte ngẫu nhiên, không bao giờ chặn nhưng có thể không ngẫu nhiên trên thiết bị mới khởi động)
  • zero (chứa một chuỗi vô hạn các byte rỗng)

Ngoài ra, bạn sẽ cần các mục cho phần cứng của mình (ngoại trừ giao diện mạng, những mục này không nhận được mục /dev): cổng nối tiếp, lưu trữ, v.v.

Đối với các thiết bị nhúng, thông thường bạn sẽ tạo các mục thiết bị trực tiếp trên hệ thống tập tin gốc. Các hệ thống cao cấp có một tập lệnh được gọi MAKEDEVđể tạo /devcác mục, nhưng trên một hệ thống nhúng, tập lệnh thường không được đưa vào hình ảnh. Nếu một số phần cứng có thể được cắm nóng (ví dụ: nếu thiết bị có cổng máy chủ USB), thì /devnên được quản lý bởi udev (bạn vẫn có thể có một bộ tối thiểu trên hệ thống tệp gốc).

Hành động thời gian khởi động

Ngoài hệ thống tập tin gốc, bạn cần gắn thêm một vài hoạt động bình thường:

  • Procfs trên /proc(khá nhiều không thể thiếu)
  • sysfs trên /sys(khá nhiều không thể thiếu)
  • tmpfsbật hệ thống tệp /tmp(để cho phép các chương trình tạo tệp tạm thời sẽ có trong RAM, thay vì trên hệ thống tệp gốc có thể ở dạng flash hoặc chỉ đọc)
  • tmpfs, devfs hoặc devtmpfs trên /devnếu động (xem udev trong các tập tin thiết bị ở trên)
  • devpts trên /dev/ptsnếu bạn muốn sử dụng [pseudo-thiết bị đầu cuối (xem nhận xét về ptsở trên)

Bạn có thể tạo một /etc/fstabtập tin và gọi điện mount -a, hoặc chạy mountthủ công.

Bắt đầu một trình nền syslog (cũng như klogdcho các bản ghi kernel, nếu syslogdchương trình không quan tâm đến nó), nếu bạn có bất kỳ nơi nào để ghi nhật ký.

Sau này, thiết bị đã sẵn sàng để bắt đầu các dịch vụ dành riêng cho ứng dụng.

Làm thế nào để tạo một hệ thống tập tin gốc

Đây là một câu chuyện dài và đa dạng, vì vậy tất cả những gì tôi sẽ làm ở đây là đưa ra một vài gợi ý.

Hệ thống tệp gốc có thể được giữ trong RAM (được tải từ hình ảnh (thường được nén) trong ROM hoặc flash) hoặc trên hệ thống tệp dựa trên đĩa (được lưu trữ trong ROM hoặc flash) hoặc được tải từ mạng (thường qua TFTP ) . Nếu hệ thống tập tin gốc nằm trong RAM, hãy biến nó thành initramfs - hệ thống tập tin RAM có nội dung được tạo khi khởi động.

Nhiều khung tồn tại để lắp ráp hình ảnh gốc cho các hệ thống nhúng. Có một vài gợi ý trong Câu hỏi thường gặp về BusyBox . Buildroot là một hình ảnh phổ biến, cho phép bạn xây dựng toàn bộ hình ảnh gốc với thiết lập tương tự như nhân Linux và BusyBox. OpenEmbedded là một khung như vậy.

Wikipedia có một danh sách (chưa đầy đủ) các bản phân phối Linux nhúng phổ biến . Một ví dụ về Linux nhúng mà bạn có thể có gần bạn là nhóm hệ điều hành OpenWrt dành cho các thiết bị mạng (phổ biến trên các bộ định tuyến gia đình của tinkerer). Nếu bạn muốn học hỏi bằng kinh nghiệm, bạn có thể dùng thử Linux từ Scratch , nhưng nó hướng đến các hệ thống máy tính để bàn dành cho người có sở thích hơn là hướng tới các thiết bị nhúng.

Một lưu ý về nhân Linux và Linux

Hành vi duy nhất được đưa vào nhân Linux là chương trình đầu tiên được khởi chạy khi khởi động. (Tôi sẽ không nhận được sự tinh tế của initrdinitramfs ở đây.) Chương trình này, theo truyền thống được gọi là init , có ID ID 1 và có các đặc quyền nhất định (miễn nhiễm với tín hiệu KILL ) và trách nhiệm (gặt hái trẻ mồ côi ). Bạn có thể chạy một hệ thống với một hạt nhân Linux và bắt đầu bất cứ điều gì bạn muốn là quá trình đầu tiên, nhưng sau đó những gì bạn có là một hệ điều hành dựa trên Linux kernel, và không phải những gì thường được gọi là “Linux” -  Linux , theo nghĩa thông thường của thuật ngữ này, là một hệ điều hành giống Unix có kernel là kernel Linux. Ví dụ, Android là một hệ điều hành không giống Unix mà dựa trên nhân Linux.


Câu trả lời tuyệt vời. Tôi chỉ đề cập đến việc khởi động vào Linux trong tiêu đề b / c đó là những gì có khả năng sẽ được tìm kiếm, vì vậy bổ sung tuyệt vời về Linux vs Linux Kernel, cần phải có kiến ​​thức rộng rãi hơn.
MDMoore313

@BigHomie Hãy nhớ rằng, Tổ chức Phần mềm Tự do muốn tất cả chúng ta gọi nó là GNU / Linux, vì trên hầu hết (tất cả?) "Linux distro" phần mềm là GNU, mặc dù hạt nhân là Linux (do đó là GNU / Linux).
BenjiWiebe

Meh, không ai có thời gian cho việc đó. Sau đó, bản phân phối của tôi nên được gọi là Busybox / Linux ?? Tôi biết tôi biết, đó không phải là bạn Stallworth, chỉ cần trút giận;)
MDMoore313

1
@BenjiWiebe Hoặc GNU / X11 / Apache / Linux / TeX / Perl / Python / FreeCiv . Ngoài RMS, mọi người gọi nó là Linux Linux.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Vâng, ngoài Debian, tôi đoán vậy. :)
một CVn

5

Tất cả những gì bạn cần là một tệp thực thi được liên kết tĩnh, được đặt trên hệ thống tệp, tách biệt. Bạn không cần bất kỳ tập tin khác. Thực thi đó là quá trình init. Nó có thể là busybox. Điều đó cung cấp cho bạn một vỏ và một loạt các tiện ích khác, tất cả trong chính nó. Bạn có thể đi đến một hệ thống hoạt động đầy đủ chỉ bằng cách thực hiện các lệnh thủ công trong busybox để gắn kết hệ thống tập tin gốc đọc-ghi, tạo / dev nút, thực thi init thực, v.v.


Vâng, tôi biết busybox đã đến rồi. Hãy xem nếu có gì khác xuất hiện.
MDMoore313

4

Nếu bạn không cần bất kỳ tiện ích shell nào, một mkshnhị phân được liên kết tĩnh (ví dụ: chống lại klibc - 130K trên Linux / i386) sẽ làm được. Bạn cần một /linuxrchoặc /inithoặc /sbin/inittập lệnh chỉ gọi mksh -l -T!/dev/tty1trong một vòng lặp:

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

Các -T!$ttytùy chọn là một bổ sung gần đây để mkshmà nói với nó để đẻ trứng một vỏ mới trên thiết bị đầu cuối đưa ra và chờ đợi nó. (Trước đó, chỉ có -T-để dæmonise một programm và -T$ttyđể đẻ trứng trên một thiết bị đầu cuối nhưng không chờ đợi cho nó. Đây không phải là rất tốt đẹp.) Các -ltùy chọn chỉ đơn giản nói với nó để chạy một shell đăng nhập (mà đọc /etc/profile, ~/.profile~/.mkshrc).

Điều này giả định thiết bị đầu cuối của bạn là /dev/tty1, thay thế. (Với nhiều phép thuật hơn, thiết bị đầu cuối có thể tự động được tìm ra. /dev/consoleSẽ không cung cấp cho bạn toàn quyền kiểm soát công việc.)

Bạn cần một vài tập tin /devđể làm việc này:

  • / dev / bảng điều khiển
  • / dev / null
  • / dev / tty
  • / dev / tty1

Khởi động với tùy chọn kernel devtmpfs.mount=1loại bỏ sự cần thiết phải điền /dev, chỉ cần để nó là một thư mục trống (thích hợp để sử dụng như một mountpoint).

Thông thường bạn sẽ muốn có một số tiện ích (từ klibc, busybox, beastiebox, toybox hoặc toolbox), nhưng chúng không thực sự cần thiết.

Bạn có thể muốn thêm một ~/.mkshrctệp, thiết lập $ PS1 và một số bí danh và hàm cơ bản.

Tôi đã từng thực hiện một initrd nén 171K (371K không nén) cho Linux / m68k bằng mksh (và tệp mkshrc mẫu của nó) và chỉ klibc-utils. (Tuy nhiên, đây là trước khi -T! Được thêm vào shell, vì vậy, nó đã sinh ra shell đăng nhập /dev/tty2thay vào đó và lặp lại một thông báo tới bảng điều khiển thông báo cho người dùng chuyển đổi thiết bị đầu cuối.) Nó hoạt động tốt.

Đây là một thiết lập tối thiểu thực sự trần . Các câu trả lời khác cung cấp lời khuyên tuyệt vời đối với các hệ thống có tính năng hơn. Đây là một trường hợp đặc biệt thực sự.

Tuyên bố miễn trừ trách nhiệm: Tôi là nhà phát triển mksh.


Đây là một câu trả lời tuyệt vời, cảm ơn vì đã chia sẻ và cũng cảm ơn vì mksh.
JoshuaRLi

2

Tối thiểu init xin chào chương trình thế giới từng bước

nhập mô tả hình ảnh ở đây

Biên dịch một thế giới xin chào mà không có bất kỳ sự phụ thuộc nào kết thúc trong một vòng lặp vô hạn. 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

Chúng tôi không thể sử dụng sys_exit, hoặc nếu không thì sự hoảng loạn hạt nhân.

Sau đó:

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"

Điều này tạo ra một hệ thống tập tin với thế giới xin chào của chúng tôi tại /init, đây là chương trình người dùng đầu tiên mà kernel sẽ chạy. Chúng tôi cũng có thể đã thêm nhiều tệp vào d/và chúng có thể truy cập được từ /initchương trình khi kernel chạy.

Sau đó cdvào cây nhân Linux, xây dựng như bình thường và chạy nó trong 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"

Và bạn sẽ thấy một dòng:

FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR

trên màn hình giả lập! Lưu ý rằng nó không phải là dòng cuối cùng, vì vậy bạn phải nhìn xa hơn một chút.

Bạn cũng có thể sử dụng các chương trình C nếu bạn liên kết chúng tĩnh:

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

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

với:

gcc -static init.c -o init

Bạn có thể chạy trên phần cứng thực với bật USB /dev/sdXvà:

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

Nguồn tuyệt vời về chủ đề này: http://landley.net/wr/rootfs-howto.html Nó cũng giải thích cách sử dụng gen_initramfs_list.sh, đó là một tập lệnh từ cây nguồn Linux để giúp tự động hóa quy trình.

Bước tiếp theo: thiết lập BusyBox để bạn có thể tương tác với hệ thống: https://github.com/cirosantilli/runlinux

Đã thử nghiệm trên Ubuntu 16.10, QEMU 2.6.1.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.