임베디드 디바이스에서 루트 파일시스템은 상당히 중요한 부분을 차지하고 있음에도 불구하고 지금까지 대부분의 관련 서적에서 이에 대한 자세한 내용은 다루지 않았었다.
대부분 기존에 이미 만들어진 파일시스템을 가져다가 사용하는 방법이었다. 여기서는 직접 루트 파일시스템을 만드는 과정을 하나하나 설명한다.

앞서 루트 파일 시스템이 중요하다고 언급한 이유는 단순히 필요한 파일을 만들고 복사하는 것을 넘어서서 전체적인 임베디드 리눅스 시스템에 대한 이해가 선행되어져야 하기 때문이다.
또한 정해진 플래시 메모리 사이즈에 맞는 루트 파일시스템을 만들기 위해서는 최적화 작업이 필요하다.

준비 운동하기

호스트에서 루트 파일 시스템을 만들 때는 루트 권한을 사용한다. 따라서 루트 파일 시스템을 제작할 때 실수로 호스트의 루트 파일 시스템을 손상하지 않도록 주의한다.

다음은 루트 파일 시스템을 제작하는 절차이다.

  1. 루트 파일 시스템 디렉토리 생성 - /sbin, /bin, /usr, /etc 등 루트 파일시스템에 필요한 디렉토리를 생성한다.
  2. 디바이스 파일 생성 - /dev/console, /dev/null 등 디바이스 파일을 mknod 명령으로 만든다.
  3. 라이브러리 설치 - 애플리케이션에 사용되는 glibc 를 비롯한 공유 라이브러리를 설치한다.
  4. 초기화 프로그램 및 환경 설정 파일 설치 - System V init 를 비롯하여 /etc/ 디렉토리의 시스템 동작에 필요한 환경을 설정하는 파일을 설치한다.
  5. 쉘과 시스템 유틸리티 설치 - 쉘(bash 등)과 쉘에서 사용되는 유틸리티, free 등의 시스템 유틸리티, cd 등의 파일관련 유틸리티를 설치한다.
  6. 응용 프로그램 설치 - 시스템에 필요한 다양한 애플리케이션 및 사용자 프로그램을 빌드하고 /bin 또는 /usr/bin 디렉토리에 설치한다.
  7. 모듈 오브젝트 설치 - 모듈 프로그램이 사용되는 경우 모듈 오브젝트를 /lib/modules 디렉토리에 설치한다.
  8. 루트 파일 시스템 이미지 생성 - 루트 파일시스템 패키징 툴(mkfs 등)을 사용하여 루트 파일시스템 이미지를 생성한다.

디렉토리 생성

루트 파일시스템 제작에 반드시 필요한 디렉토리는 아래와 같다.

디렉토리 내용
/etc 시스템 설정 파일, 예를들면 /etc/inetd.conf, /etc/inittab, /etc/fstab, /etc/rc.d/rc.sysinit 등을 저장한다. 이 디렉토리에 있는 파일들은 시스템을 운영하는 방법을 지정하기 때문에 중요하다
/sbin 시스템 관리 명령을 가지고 있는 디렉토리로 init, sh, insmod 등을 저장한다. 이 디렉토리에 있는 모든 명령은 다른 디렉토리에서 컴파일한 후에 복사한다
/bin 시스템의 기초 명령, 예를 들면 gzip, su, tar, rpm, vi, mount 등을 저장한다. 명령들은 다른 디렉토리에서 컴파일한 후 복사된다
/dev /dev/console, /dev/null 등의 디바이스 파일을 가지는 디렉토리. 이 디렉토리에 있는 디바이스 노드들은 mknod 명령에 의해서 만들어진다. 하지만 모든 노드를 만들 필요는 없고 필요한 일부 노드만 만든 후 부팅과정에서 udev 를 이용하여 필요한 노드를 자동으로 생성한다
/lib 시스템 라이브러리 디렉토리로 공유 라이브러리와 모듈을 저장한다
/usr 사용자 애플리케이션이 설치되는 디렉토리로 외부에서 빌드한 후 복사된다
/proc 디렉토리만 만들면 커널 부팅 과정에서 proc 파일시스템에 마운트 된다
/sys 디렉토리만 만들면 커널 부팅 과정에서 sysfs 파일시스템에 마운트 된다

아래와 같이 생성한다.

#cd /tmp
#mkdir myroot
#cd myroot
#mkdir -p etc sbin bin dev lib lib/modules usr usr/bin usr/sbin opt proc sys mnt home root tmp var var/log var/run/utmp var/run/wtmp var/lock var/lock/subsys

디바이스 파일 생성

루트 권한으로 mknod 명령어를 사용한다.

#cd /tmp/myroot/dev
#mknod console c 5 1
#mknod null c 1 3

디바이스 파일을 만들 때는 null 이나 console 디바이스와 같이 부팅에 필요한 일부 디바이스 파일만 만들면 나머지 필요한 디바이스 파일은 시스템 부팅 과정에서 UDEV(User Space device filesystem)을 사용하여 자동으로 생성할 수 있다.

라이브러리 설치

  1. 리눅스 루트 파일 시스템의 /lib 디렉토리에서는 아래와 같은 파일이 있다.
  2. 실제의 라이브러리 파일 - 실제 애플리케이션에서 사용되는 공유 라이브러리로 libLIBRARY_NAME-GLIBC_VERSION.so 형식의 이름으로 저장된다.
  3. 주요 개정 번호를 가진 심볼 링크 - 실제 라이브러리의 심볼 링크로 주개정 번호를 포함하여 libLIBRARY_NAME.so.MAJOR_REVISION_VERSION 형식의 이름으로 저장된다.
  4. 개정 번호에 무관한 심볼 링크 - 개정 번호나 glibc 버전에 무관하게 접근할 수 있는 방법을 제시하기 위해 libLIBRARY_NAME.so 형식의 이름으로 심볼 링크 파일을 저장한다.
  5. 정적 라이브러리 - 정적으로 사용되는 라이브러리다. 애플리케이션에 추가되어 사용되는 라이브러리로 libLIBRARY_NAME.a 형식의 이름으로 저장된다. 하지만 임베디드 리눅스는 타겟에서 정적인 라이브러리를 사용하여 새로운 애플리케이션을 빌드할 일이 없기 때문에 이 형식의 파일은 저장되지 않는다.

위와 같은 여러 종류의 파일을 루트 파일시스템의 lib 디렉토리에 설치하기 위해 개발자는 생성된 실제 라이브러리를 복사하고 lib 디렉토리에 링크를 생성한다. 라이브러리를 복사할 때는 스트립을 해서 불필요한 심볼을 제거해야 루트파일 시스템의 용량을 줄일 수 있다.
스트립은 arm-none-linux-gnueabi-strip 명령을 사용하거나 arm-none-linux-gnueabi-objcopy 명령과 -strip-all 옵션을 사용한다.

툴 디렉토리(/root/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/arm-none-linux-gnueabi)에 있는 라이브러리를 설치한다면 다음과 같이 실행한다. 여기서 설치라 함은 툴체인에 있는 라이브러리 파일을 복사하는 것을 뜻한다.

#cd /tmp/myroot/lib
#cp -a /root/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/arm-none-linux-gnueabi/libc/ld-2.15.so .
#cp -a /root/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/arm-none-linux-gnueabi/libc/lib/ld-linux.so.3 .
#arm-none-linux-gnueabi-strip ld-2.15.so
#cp -a /root/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/arm-none-linux-gnueabi/libc/lib/libc-2.15.so .
#cp -a /root/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/arm-none-linux-gnueabi/libc/lib/libc.so.6 .
#arm-none-linux-gnueabi-strip libc-2.15.so
#ln -s libc-2.15.so libc.so

공유라이브러리를 사용하는 경우에는 /etc/ld.so.conf 파일을 만든다. /etc/ld.so.conf 파일의 내용은 다음과 같다.

/lib
/usr/lib

필요에 따라서는 ldconfig 명령을 이용하여 공유 라이브러리 사용에 필요한 링크와 캐시 정보를 만든다. 임베디드 리눅스에서는 호스트의 ldconfig 를 사용하고 대상 디렉토리를 지정하여 사용할 수도 있다.

Busybox 설치

리눅스에 부팅에 필요한 유틸리티들이 필요하다.
필요한 프로그램들을 일일이 크로스컴파일하여 복사할 수도 있겠지만, 갯수가 많아지면 상당히 번거로운 작업이 될 것이다.
이를 해결하기위해 여기서는 busybox 를 사용한다.

UDEV 설치

UDEV(User space device)는 hotplug 시스템의 일부로 커널에 등록된 디바이스의 디바이스 파일(노드)을 사용자 영역에서 자동으로 만든다. UDEV 를 사용하려면 반드시 커널은 sysfs 파일시스템을 지원하고 /sys 디렉토리에 마운트되어 있어야 하고, proc 파일시스템은 /proc 파일시스템에 마운트되어 있어야 하며, 리눅스 네트워크 서브시스템의 UNIX 도메인 소켓을 지원해야 한다. 모듈 프로그래밍을 이용하여 새로운 디바이스가 커널에 등록되면 리눅스 네트워크 서브시스템의 UNIX 도메인 소켓을 이용하여 이벤트를 UDEV 로 전달하고, 이 이벤트에 따라 sysfs 파일시스템의 정보를 사용하여 디바이스 파일을 자동으로 생성한다.

UDEV 는 디바이스 파일을 생성하는 역할을 담당하며, 커널에서 보낸 hotplug 이벤트는 /bin/hotplug 에 의해 처리된다.
UDEV 를 사용하는 경우에는 필요에 따라서 /etc/udev/rules.d/udev.rules 파일에 디바이스 파일을 생성하는 규칙을 만들어 사용할 수 있다.
다음은 tty 장치를 위한 규칙 파일을 보여준다.

#tty devices
KERNEL == "ttySAC[0-2]*", NAME = "tts/%n", SYMLINK = "%k"

위 규칙은 커널에 ttySAC 라는 장치 이름이 사용될 때 다음과 같이 동작한다.

  1. udev 는 /dev 디렉토리에 부번호에 따라 tts/0, tts/1, tts/2 라는 이름으로 디바이스 파일(노드)을 생성한다.
  2. 커널의 장치 이름을 사용하여 /dev 디렉토리에 ttySAC0, ttySAC1, ttySAC2 이름을 가지는 디바이스 파일이 심볼릭 링크로 만들어진다.
  3. KERNEL == “ttySAC[0-2]*” 은 매치(match) 조건을 나타내고, NAME = “tts/%n” 과 SYMLINK = “%k” 는 매치 조건이 만족할 경우 실행될 항목(action assignment)을 나타낸다.

이와 같이 UDEV 규칙 파일은 다음과 같은 표준 형식을 가지고 구성된다.

match[, <match>]*, assignment[, <assignment>]*

매치(match)는 조건을 나타내고, 실행될 항목(assignment)은 매치 조건이 성립되는 경우 실행될 동작을 지정한다. 매치조건은 1개 이상이 될 수 있고, 실행 항목 역시 1개 이상으로 구성된다.

매치 조건을 명시할 때, '==' 앞에 있는 KERNEL 과 같은 문자열을 매치 키(key)라고 하는데 KERNEL 을 비롯하여 SUBSYSTEM, DRIVER 를 사용할 수 있다.

매치키 내용
KERNEL 커널에서 사용하는 장치이름
SUBSYSTEM 장치가 속한 서브 시스템
DRIVER 장치 드라이버의 이름

실행 항목을 지정하는 경우에도 NAME 또는 SYMLINK 와 같은 항목 키값을 지정할 수 있다. NAME 은 생성할 장치의 디바이스 파일 이름을 지정하고, SYMLINK 는 NAME 외의 심볼릭 링크로 생성할 이름을 지정한다. 실행 항목에서 사용된 %n 은 장치 번호, %k 는 커널의 장치이름을 사용함을 나타낸다.

다음은 앞서 예로든 규칙에 따라 생성된 디바이스 파일 /dev/tts 디렉토리 1,2,3 과 /dev 디렉토리의 심볼릭 링크 ttySAC0, ttySAC1, ttySAC2, ttySAC3 을 보여준다.

UDEV 소스코드를 내려받아 ARM 타겟으로 컴파일하여 사용하면 된다.

애플리케이션 설치

앞서 설명한 프로그램들과는 별도로 루트파일 시스템에 추가해야할 유틸리티가 있다면, 별도로 빌드하여 bin 또는 usr/bin 에 설치한다.

모듈 오브젝트 설치

일반적으로 커널에서 모듈을 사용하는 경우에는 모듈 오브젝트를 루트 파일시스템에 설치한다. 모듈은 /lib/modules 디렉토리에 커널 버전에 따라 설치된다.
참고로 모듈 오브젝트는 .ko 확장자를 가진다.

루트 파일시스템 이미지 생성

앞서의 과정에 따라서 만들어진 루트 파일 시스템은 하나의 이미지로 만들어진 다음에 타겟의 주메모리, 플래시 메모리, SD 메모리 카드와 같은 저장 장치에 저장된 후 부팅 과정에서 지정된 파일 시스템으로 마운트되어 사용된다.

파일시스템의 종류에는 여러가지가 있는데, 마운트 속도라든지 동작 속도, 동작 방식, 성능 등 다양한 차이가 있기 때문에 시스템의 요구사항에 맞는 파일 시스템을 선택하여 사용하면 된다.

여기서는 RAM 디스크 기반의 ext3 파일시스템으로 루트 파일시스템을 생성하는 방법을 설명한다. RAM 디스크는 리눅스 커널에서 기본적으로 지원하는 저장 장치다.
따라서 별도의 블록 디바이스 드라이버의 포팅없이 사용이 가능하며, 루트 파일 시스템이 저장되는 RAM 디스크 장치 이름은 /dev/ram0 이다.

RAM 디스크를 루트파일 시스템으로 사용하게 해주는 방법을 INITRD(Initial RAM Disk)라 한다.

RAM 디스크 이미지는 하나의 디스크 파일을 만들고, 빌드하고 준비한 모든 애플리케이션과 파일을 이미지에 채워 넣은 것이다. 이때 하나의 파일을 디스크와 같이 사용하도록 해주는 것을 루프백 디바이스라고 한다.

호스트 PC 에서 루프백 디바이스는 dd 명령어로 만들 수 있다. 아래는 블록 크기가 1 KB 이며, 총 8192 개의 블록으로 구성된 8 MB 크기의 루프백 디바이스 파일로 ramdisk 를 생성하는 명령이다.

#dd if=/dev/zero of=ramdisk bs=1k count=8192

루프백 디바이스는 하드디스크와 같은 일반 저장 장치를 특정 파일 시스템으로 만들어 주고, 호스트 PC 의 디렉토리에 마운트하여 그 내부에 데이터를 읽고 쓸 수 있다. 생성된 파일 ramdisk 를 ext3 파일시스템으로 만들기 위해 mkfs 명령을 사용하여 다음과 같이 명령한다.

/sbin/mkfs -t ext3 ramdisk

호스트 PC 의 tmp_ramdisk 디렉토리에 ramdisk 를 마운트 해보자. 이때 tmp_ramdisk 디렉토리는 마운트에 앞서 만들어져 있어야 한다.

#mount -o loop -t ext3 ramdisk tmp_ramdisk

이후 필요한 파일을 복사하게 되는데, 이렇게 생성된 애플리케이션과 파일은 많은 속성을 가지고 있고, 일부 파일은 심볼릭 링크가 되며, 하위 디렉토리까지 모든 파일과 디렉토리를 복사해야 한다. 따라서 생성된 애플리케이션과 데이터 파일을 cp 명령으로 그냥 복사하면 안되고, 모든 파일 및 디렉토리의 속성을 그대로 복사해야 한다.
이와 같은 이유로 cp 명령 대신에 cpio 명령을 사용하는 것이 일반적이다. 다음은 파일시스템 애플리케이션과 데이터 파일을 가지는 myroot 디렉토리의 모든 파일과 하위 디렉토리를 찾아서 cpio 명령으로 tmp_ramdisk 디렉토리에 복사하는 명령의 조합을 보여준다.

#cd myroot
#find . -print0 | cpio -p0dm ../tmp_ramdisk
#cd ../

위 명령어는 루트 파일시스템 애플리케이션(myroot)과 데이터 파일을 가지는 디렉토리와 루프백 디바이스 파일(ramdisk)을 마운트한 tmp_ramdisk 디렉토리가 같은 디렉토리에 존재한다는 가정하에 예로 든 것이다.

위 과정에 의해 이미 루프백 디바이스 파일 ramdisk 내부에 루트파일 시스템의 모든 파일과 디렉토리가 복사되었다. 따라서 이 파일을 그대로 루트파일 시스템으로 사용할 수도 있다.
하지만 대부분은 루트파일시스템의 이미지 크기를 줄이기 위해서 압축하여 사용한다. 압축은 여러 방식이 있으나 일반적으로 gzip 방식을 많이 사용한다.
다음은 gzip을 이용하여 압축을 실행하는 명령으로, 이 명령의 실행이 끝난 경우에는 ramdisk 파일은 없어지고 ramdisk.gz 이라는 파일이 만들어진 것을 볼 수 있다.
압축을 실행하기 전에는 tmp_ramdisk 와 마운트된 것을 먼저 언마운트한 후에 실행된다.

#umount tmp_ramdisk
#gzip -v ramdisk

이제 생성되고 압축된 루트 파일시스템 이미지 ramdisk.gz 를 타겟의 메모리로 탑재해서 사용하면 새롭게 만들어진 루트 파일시스템 이미지가 사용되는 것이다.
다음은 앞서 과정을 mkdisk 라는 스크립트로 만든 것이다.

echo ">>> This script create a ARM Linux RAMDISK <<<"
 
rm -f ramdisk.gz
 
echo ">> Create loopback device file and mount"
echo "> Create 8192 block count of loopback device file ramdisk"
echo "> The each block size is 1k, the total size of ramdisk is 8MB"
dd if=/dev/zero of=ramdisk bs=1k count=8192
 
echo "> Make ramdisk to ext3 filesystem"
/sbin/mkfs -t ext3 ramdisk
 
echo "> mount loopback device file ramdisk to tmp_ramdisk"
mkdir tmp_ramdisk
mount -o loop -t ext3 ramdisk tmp_ramdisk
 
echo ">> Create RAMDISK image"
echo "> copy all file to tmp_ramdisk"
cd myroot
find . -print0 | cpio -p0dm ../tmp_ramdisk
cd ../
umount tmp_ramdisk
 
echo "> compress ramdisk image"
gzip -v ramdisk
 
rmdir tmp_ramdisk

사용방법은 다음과 같다.

#cd /root/Work/
#ls
mkdisk myroot
#sh mkdisk
#ls
myroot ramdisk.gz

만일 앞서 루트파일시스템 빌드 과정에서 RAM 디스크 용량이 8MB 를 넘는 경우에는 불 필요한 파일을 삭제하거나 루프백 디바이스 파일의 크기를 키워서 사용해야 한다.











시스템 동작 환경 변수 설정

시스템 동작 환경 변수는 /etc 디렉토리에 있는 다양한 파일을 말하며, 리눅스 시스템의 동작에 필요한 환경 변수 파일은 매우 다양하다.

디렉토리 및 파일 내용
HOSTNAME 머신 이름 지정
fstab 고정된 파일시스템 정보
group 그룹 정보 파일
passwd 사용자 계정 및 비밀번호 지정 파일
hosts 호스트 이름과 주소 지정
inetd.conf 네트워크 서버 설정 옵션
inittab 리눅스 머신 런레벨 및 초기 동작 지정 파일
issue 머신 시작 문자열 지정
ld.so.conf 공유 라이브러리 정보 지정
mtab 마운트 방법 및 형식 지정
resolv.conf DNS 서버 지정
services 네트워크 TCP/UDP 서비스 지정
syslog.conf 시스템 로깅 콘솔 지정
profile 시스템 시작 단계에서 환경 변수 설정
rc.d/rc.M 다중 사용자 스크립트 지정
rc.d/rc.S 단일 사용자 스크립트 지정
rc.d/rc.hotplug 핫 플러그 동작을 위한 스크립트 지정
rc.d/rc.local 로컬 사용자 스크립트 지정
rc.d/rc.udev UDEV 동작을 위한 스크립트 지정
hotplug.d 핫플러그 동작 스크립트
hotplug.d/default.hotplug 기본 핫플러그 동작 스크립트
udev/rules.d/udev.rules UDEV 룰 지정
udev/udev.conf UDEV 동작 환경을 구성한 파일

안드로이드의 루트 파일 시스템 구조

디렉토리 내용
/dev /dev/console, /dev/null 등의 디바이스 파일을 가지는 디렉토리
/etc 시스템 설정 파일등을 저장하는 디렉토리
/mnt 다른 미디어 장치와 마운트 되어 사용되는 디렉토리
/proc proc 파일시스템에 마운트 되어 사용되는 디렉토리
/sbin 시스템 관리 명령을 가지고 있는 디렉토리
/sys sysfs 파일시스템에 마운트 되어 사용되는 디렉토리
/data anr, app, backup, dalvik-cache 등 다양한 사용자 데이터와 리소스를 가지는 디렉토리
/system app, bin, etc, fonts, framework, lib 등 안드로이드 관련 핵심 요소를 가지고 있는 디렉토리
/vendor 벤더 관련 소스를 가지는 디렉토리
/tmp 임시파일을 저장하는 디렉토리
  • computer/embedded/루트_파일시스템_만들기.txt
  • Last modified: 3 years ago
  • by likewind