これはユーザー空間アプリケーションに関する質問です。私の言葉を聞いてください!
おそらく、Linuxの機能的なディストリビューションを実行するには、3つの「アプリケーション」が必要です。
ブートローダ - 組み込み用、通常U-Bootですが、厳しい要件ではありません。
カーネル - 非常に簡単です。
ルートファイルシステム - それがなければ、シェルで起動することは不可能です。カーネルが起動するformというファイルシステムが含まれています
init
。
私の質問は#3についてです。誰かが非常に最小限のrootfsを構築したい場合(この質問ではGUIがなく、シェルしかないと仮定します)、シェルから起動するにはどのファイル/プログラムが必要ですか?
答え1
それはすべてあなたのデバイスで使用したいサービスによって異なります。
プログラム
Linuxを直接起動できます。シェル。本番環境ではあまり役に立ちません(単にシェルをしたい人)。ただし、対話型ブートローダがある場合は介入メカニズムとして役立ちます。つまり、init=/bin/sh
カーネルコマンドラインに渡されます。すべてのLinuxシステム(およびすべてのUnixシステム)には/bin/sh
。
セットが必要ですシェルユーティリティ。忙しい箱非常に一般的な選択です。シェルを含み、ファイルおよびテキスト操作(cp
、、、grep
...)、ネットワーク設定(ping
、、、ifconfig
...)、プロセス操作(ps
、、、nice
...)などのさまざまなシステムで一般的に使用されます。ツール用のユーティリティ(fdisk
、、、、mount
...)を使用しました。syslogd
BusyBoxは非常に設定可能です。コンパイル時に必要なツールや個々の機能を選択して、アプリケーションに適したサイズ/機能トレードオフを得ることができます。その他はsh
ありません ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 、、、、、、、、、、BusyBoxmount
はumount
、各ユーティリティへのシンボリックリンクを持つ単一のバイナリとしてインストールされます。halt
cat
cp
mv
rm
mkdir
rmdir
ps
sync
busybox
一般的なUNIXシステムの最初のプロセスは次のとおりです。init
。その使命は、他のサービスを開始することです。 BusyBoxには初期化システムが含まれています。init
バイナリ(通常は存在する)に加えて、起動する/sbin
構成ファイル(通常は呼び出される/etc/inittab
最新の初期化の置き換えではこのファイルを削除しますが、小規模の組み込みシステムでは見つかりません)も必要です。サービスは提供されますか? BusyBoxの場合は/etc/inittab
オプションです。見つからない場合は、コンソールにルートシェルが作成され、/etc/init.d/rcS
起動時にスクリプトが実行されます(デフォルトの場所)。
もちろん、デバイスが役に立つタスクを実行できるようにするプログラムを除いて、これが必要なすべてです。たとえば、私の家のルーターで実行されています。OpenWrtバリエーションでは、唯一のプログラムはBusyBox nvram
(NVRAMの設定を読み、変更するために使用されます)とネットワークユーティリティです。
すべての実行可能ファイルが静的にリンクされていない限り、動的ローダ(ld.so
libcの選択とプロセッサアーキテクチャによって異なる名前で呼び出すことができます)が必要です。動的ライブラリ(/lib/lib*.so
そしておそらくそれらのいくつかも/usr/lib
)これらの実行可能ファイルに必要です。
ディレクトリ構造
これファイルシステム階層標準Linuxシステムの一般的なディレクトリ構造について説明します。デスクトップとサーバーのインストールの両方で機能します。組み込みシステムでは、多くの部分を省略できます。これは一般的な最小値です。
/bin
:実行可能プログラム(一部は含まれている可能性があります/usr/bin
)/dev
:デバイスノード(下記参照)/etc
:構成ファイル/lib
:動的ローダを含む共有ライブラリ(すべての実行可能ファイルが静的にリンクされていない場合)/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
Create /dev
Entryというスクリプトがありますが、組み込みシステムでは通常、このスクリプトは画像にバンドルされていません。一部のハードウェアがホットスワップ可能な場合(たとえば、デバイスにUSBホストポートがある場合/dev
)ウデブ(ルートファイルシステムにはまだ最小限の設定があるかもしれません)。
起動時の作業
正しい操作を行うには、ルートファイルシステムに加えていくつかのファイルシステムをマウントする必要があります。
- プロセスファイルシステム(ほぼ
/proc
必須) - システムファイルシステム(ほぼ
/sys
必須) tmpfs
ファイルシステムを開く/tmp
(プログラムはフラッシュまたは読み取り専用のルートファイルシステムではなくRAMに一時ファイルを作成できます)- 動的な場合は、tmpfs、devfs、またはdevtmpfs
/dev
(上記の「デバイスファイル」のudevを参照) - 開発者使用するには、[医師端末]をオンにしてください
/dev/pts
(上記の注意事項を参照pts
)。
あなたは一つ作ることができます/etc/fstab
ファイルを保存して呼び出すか、mount -a
手動mount
で実行してください。
始めるシステムログログを書き込む場所がある場合はデーモン(およびプログラムが処理しないklogd
場合はカーネルログ)。syslogd
その後、デバイスはアプリケーション固有のサービスを開始する準備が整います。
ルートファイルシステムの作成方法
長くて多様な話なので、ここではいくつかの提案をしたいと思います。
ルートファイルシステムは、RAM(通常はROMまたはフラッシュメモリの(一般的に圧縮された)イメージからロード)、またはディスクベースのファイルシステム(ROMまたはフラッシュメモリに保存)に保存するか、ネットワークからロード(通常は次を介してロード)できます。ネットワーク) 。TFTP)適用される場合。ルートファイルシステムがRAMにある場合は、次のように設定します。ファイルシステムの初期化- 起動時にコンテンツが生成されるRAMファイルシステム。
組み込みシステム用のルートイメージを組み合わせるために使用できる多くのフレームワークがあります。その中にいくつかのヒントがありますビジボックスFAQ。ルート構築Linux カーネルや BusyBox と同様の設定を使用して、ルートイメージ全体を構築できる人気のあるイメージです。オープン埋め込みもう一つのフレームワークです。
Wikipediaには人気のある(不完全な)リストがあります。組み込みLinuxディストリビューション。近くにある可能性のある組み込みLinuxの例は次のとおりです。OpenWrtネットワークデバイス用のオペレーティングシステムスイートです(Tinkererホームルーターで人気があります)。経験で学びたいなら試してみることができます最初からLinuxしかし、これは組み込みデバイスではなく、趣味のデスクトップシステムを目指しています。
Linux および Linux カーネルに関する注意事項
Linuxカーネルに含まれる唯一の動作は、起動時に最初のプログラムを実行することです。 (私は入りません。初期化プログラムそしてファイルシステムの初期化ここに微妙さ。 )この手順は伝統的に内部に、プロセスID 1があり、特定の権限があります(影響を受けません)。キル信号)と責任(収穫幼児)。 Linuxカーネルでシステムを実行し、必要なプロセスを最初のプロセスとして起動できますが、持っているのは通常「Linux」と呼ばれるのではなく、Linuxカーネルベースのオペレーティングシステムだけです。 Linux、用語の常識的にUnixオペレーティングシステムと同様に、カーネルはLinuxカーネル。たとえば、AndroidはUnixと似ていませんが、Linuxカーネルに基づくオペレーティングシステムです。
答え2
必要なのは、ファイルシステムに別々に配置された静的にリンクされた実行可能ファイルのみです。他のファイルは必要ありません。この実行ファイルはinitプロセスです。ビジボックスかもしれません。これはシェルとその中の他の多くのユーティリティの両方を提供します。ビジボックスから手動でコマンドを実行したり、ルートファイルシステムを読み書きでマウントしたり、/ devノードを作成したり、実際の初期化を実行したりするなどの操作で、フル機能のシステムに入ります。
答え3
シェルユーティリティが必要ない場合は、静的にリンクされたmksh
バイナリ(たとえば、Linux / i386のklibc - 130K)が必要です。ループでのみ呼び出される/linuxrc
or/init
またはスクリプトが必要です/sbin/init
。mksh -l -T!/dev/tty1
#!/bin/mksh
while true; do
/bin/mksh -l -T!/dev/tty1
done
この-T!$tty
オプションは最近追加され、mksh
指定された端末に新しいシェルを作成して待機するように指示します。 (以前は-T-
プログラムをデーモン化して-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、またはツールボックスなど)が必要ですが、実際には必要ありません。
~/.mkshrc
$ PS1といくつかのデフォルトのシェルエイリアスと機能を設定するファイルを追加できます。
mksh(およびその例のmkshrcファイル)とklibc-utilsのみを使用して、Linux / m68k用の171K圧縮(371K非圧縮)initrdを作成したことがあります。 (これは-T!がシェルに追加される前であるため、ログインシェルを作成し、/dev/tty2
ユーザーに端末を切り替えるように促すメッセージをコンソールに表示します。)うまくいきます。
これは本当に最小限設定。他の答えは、よりユニークなシステムの優れた提案を提供します。これは実際に特別なケースです。
免責事項:私はmksh開発者です。
答え4
段階的最小初期化 Hello Worldプログラム
この答えが示すように、必要なのは標準ライブラリではなく静的にリンクされたELFファイルなので、単一のファイルを持つファイルシステムです。
依存関係なしで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"
/init
これにより、カーネルが実行する最初のユーザーモードプログラムであるhello worldを使用してファイルシステムが作成されます。また、より多くのファイルを追加し、カーネルの実行中にプログラムがそのファイル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.htmlgen_initramfs_list.sh
また、プロセスの自動化に役立つLinuxカーネルソースツリーのスクリプトであるこれを使用する方法についても説明します。
シェルの最小限の設定を提供します。
Buildrootは私のお気に入りのオプションです。以下の説明を参照してください。最小のLinux実装は何ですか?
この時点で基本的に標準ライブラリを扱う必要がありますが、sh
標準ライブラリなしで誰がシェルを作成しますか?したがって、いくつかの自動化スクリプトを使用してこれらすべてを設定することをお勧めします。
Ubuntu 16.10、QEMU 2.6.1でテストされました。