rdinit=<위치>
로 지정할 수 있고, default로 rdinit=/init
이다.init/main.c
에 있고, 함수 rest_init()
에서 시작한다.init=<위치>
로 지정할 수 있고, default로 /sbin/init
, /etc/init
, /bin/init
, /bin/sh
를 성공할 때 까지 차례로 실행root=/dev/<디스크이름><파티션번호>
, root=/dev/<디스크이름>p<파티션번호>
가 필요하다.root=(hd0,gpt2) -> root=UUID=<UUID>
root=/dev/mmcblk0p1
root=/dev/nfs rootfstype=nfs nfsroot=<serverip>:/nfs/client1/root,v3,tcp
PID 1
인 첫 번째 스레드를 만들고, kernel_init()
의 코드를 실행한다./init
을 찾는데 실패하면, init/do_mounts.c
안의 함수 prepare_namespace()
를 불러, 파일 시스템을 마운트하려 할 것이다./sbin/init
, /etc/init
, /bin/init
, /bin/sh
를 성공할 때까지 차례로 실행하려고 시도한다.root=
매개 변수를 통해 커널 커맨드라인에 지정된 블록 장치를 마운트함으로써 rootfs를 구한다.init
인 첫 번째 프로그램을 실행한다.rootfs를 만들기위한 요소 | 설명 |
---|---|
init | 보통 일련의 스크립트를 실행함으로, 모든 것을 시작시키는 프로그램 |
shell | init과 기타 프로그램이 호출하는 shell script를 실행하기 위해 필요하다. |
daemon | init 자체도 daemon이다.syslogd sshd 등 수많은 대몬들이 init 에의해 제어되어 실행된다. |
shared library | - |
conf 파일들 | /etc 에 저장되어 있다. |
장치 노드 | 다양한 디바이스 드라이버에 접근할 수 있게 해주는 특수 파일들 |
/proc , /sys | 커널 자료 구조를 디렉토리와 파일의 계층 구조로 나타내는 2개의 가상 파일 시스템 여러 프로그램과 라이브러리 함수들이 proc 와 sys 에 의존한다. |
커널 모듈 | /lib/modules/<kernel_version> |
init=
rdinit=
을 통해 지정된 프로그램의 존재 외에는 파일과 디렉토리의 레이아웃에 신경 쓰지 않는다.FHS | 설명 |
---|---|
/bin | 필수 바이너리 |
/dev | 디바이스 노드, 기타 특수 파일들 |
/etc | conf 파일들 |
/lib | 필수 shared library (libc ..) |
/proc | proc 파일 시스템 |
/sys | sysfs 파일 시스템 |
/sbin | 시스템(system) 에 필수 바이너리 |
/tmp | 임피 파일, 휘발성 파일들 |
/usr | 추가 프로그램. 시스템 부팅할 때 필요한 것은 담지말자 |
/var | 실행 중 변경될 수 있는 파일과 디렉토리 |
$ mkdir ~/rootfs
$ cd ~/rootfs
$ mkdir bin dev etc home lib proc sbin sys tmp usr var
$ mkdir usr/bin usr/lib usr/sbin
$ mkdir -p var/log
$ tree ./rootfs -d
./rootfs
├── bin
├── dev
├── etc
├── home
├── lib
├── proc
├── sbin
├── sys
├── tmp
├── usr
│ ├── bin
│ ├── lib
│ └── sbin
└── var
└── log
$ cd ~/rootfs
$ sudo chown -R 0:0 *
BusyBox
가 제공하는 간단한 init
을 사용한다.[applet]_main
의 형태로 export한다.cat
명령은 coreutils/cat.c
에 구현되어 있고, cat_main
을 export한다.main
함수 자체는 커맨드라인 Argument에 근거해 호출을 올바른 Applet으로 보낸다.$ busybox cat my_file.txt
$ ls -l bin/cat bin/busybox
bin/cat -> busybox
cat
을 입력했을 때, 실제로 실행되는 프로그램은 busybox 이다.argv[0]
에 전달된 명령 이름 (cat
)을 추출한 뒤에 표에서 cat
에 대응되는 cat_main
을 찾으면 된다. libbb/appletlib.c
중 아래에 나와있는 부분에 있다.applet_name = argv[0];
applet_name = bb_basename(applet_name);
run_applet_and_exit(applet_name, argv);
init
프로그램, 다양한 수준의 복잡도를 갖는 몇 가지 shell, 대부분의 관리 작업을 위한 유틸리티를 포함해 300개가 넘는 애플릿을 담고 있다.vi
편집기도 있어서 장치에 있는 텍스트파일을 수정할 수도 있다.$ git clone git://busybox.net/busybox.git
$ cd busybox
$ git checkout <사용하고픈 버전>
$ make distclean
$ make defconfig
make menuconfig
를 실행해 구성을 미세 조정하고 싶을 수도 있다.Busybox Settings > Installation Options(CONFIG_PREFIX)
에서 설치 경로가 스테이징 디렉토리(~/rootfs
)를 가리키도록 설정 하자.$ make ARCH=arm CROSS_COMPILE=arm-cortex_a8-linux-gnueabihf-
glibc
가 있는데, 상당히 크다.crossTool-NG
로 빌드한 glibc 2.22
의 경우 라이브러리, locale, 기타 지원 파일이 33MB에 달한다.musl libc
, uClibc-ng
를 사용하면 크기를 더 줄일 수 있다.readelf
로 필요 라이브러리 알아내자!$ cd ~/rootfs
$ arm-cortex_a8-linux-gnueabihf-readelf -a bin/busybox | grep "program interpreter"
[Requesting program interpreter: /lib/ld-linux-armhf.so.3]
$ arm-cortex_a8-linux-gnueabihf-readelf -a bin/busybox | grep "Shared library"
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libc.so.6]
sysroot
디렉토리에서 이들 파일을 찾아서 스테이징 디렉토리로 복사해야한다.$ arm-cortex_a8-linux-gnueabihf-gcc -print-sysroot
/home/markyang/x-tools/arm-cortex_a8-linux-gnueabihf/arm-cortex_a8-linux-gnueabihf/sysroot
/lib/ld-linux-armhf.so.3
을 보면 사실은 심볼릭 링크이다.$ cd (위의 sysroot)
$ ls -l lib/ld-linux-armhf.so.3
lrwxrwxrwx 1 markyang markyang 10 Mar 3 12:22 lib/ld-linux-armhf.so.3 -> ld-2.22.so
cp -a
를 사용해 각각을 복사한다.$ cd ~/rootfs
$ cp -a (위 sysroot)/lib/ld-linux-armhf.so.3 lib
$ cp -a (위 sysroot)/lib/ld-2.22.so lib
dlopen(3)
호출을 통해 로드되는 라이브러리(대부분 플러그인)를 놓칠 위험이 있다. 나중에 NSS(name service switch) 라이브러리의 예를 살펴보자.