2014-03-28

嘗試構建自己的busybox

來源 : http://www.360doc.com/content/13/0829/19/7377734_310794205.shtml

1、一個作為宿主機的Linux;本文使用的是Redhat Enterprise Linux 5.4;
2、在宿主機上提供一塊額外的硬盤作為新系統的存儲盤,為了降低複雜度,這裡添加使用一塊IDE接口的新硬盤;
3、Linux內核源碼,busybox源碼;本文使用的是目前最新版的linux-2.6.34.1和busybox-1.16.1。

說明:本文是一個step by step的實做指南;

一、為系統上的新硬盤建立分區

這裡根據需要先建立一個大小為100M的主分區作為新建系統的boot分區和一個512M的分區作為目標系統(即正在構建的新系統,後面將沿用此名稱)的根 分區;100M的分區格式化後將其掛載至/mnt/boot目錄下;512M的分區格式化後將掛載 至/mnt/sysroot目錄;

說明:
1、此處的boot和sysroot的掛載點目錄名稱儘量不要修改,尤其是boot目錄,否則您必須保證後面的許多步驟都做了相應的改動;
2、新建系統的boot目錄也可以跟根目錄在同一個分區,這種方式比獨立分區還要簡單些,因此這裡將不對此種方法再做出說明;

 

二、編譯內核源代碼,為新系統提供一個所需的內核(本例中的源代碼包都位於/usr/src目錄 中)

#cd /usr/src
#tar -jxvf linux-2.6.34.1.tar.bz2
#ln -sv linux-2.6.34.1 linux
#cd linux

#makemenuconfig

根據您的實際和規劃選擇所需要的功能;本實例計畫製作一個具有網絡的功能的tinylinux且不打算使用內核模塊,因此,這裡選擇把本機對應的網卡驅動直接編譯進了內核。作者使用的是 vmware Workstation虛擬機,所以,所需的網上驅動是pcnet32的,其它的均按需要選擇。選擇 完成後需要保存至當前目錄下.config文件中。 #make SUBDIR=arch/
#cp arch/x86/boot/bzImage /mnt/boot

 

三、編譯busybox

#cd /usr/src
#tar -jxvf busybox-1.16.1.tar.bz2
#cd busybox-1.16.1
#make defconfig
#make menuconfig

說明:
1、此處需要選擇 Busybox Setings->Build Options-> Build BusyBox as a static binary (no shared libs),這樣可以把Busybox編譯成一個不使用共享庫的靜態二進制文件,從而避免了對 宿主機的共享庫產生依賴;但你也可以不選擇此項,而完成編譯後把其依賴的共享庫複製至目標系統上的/lib目錄中即可;這裡採用前一種辦法。
2、修改安裝位置為/mnt/sysroot;方法為:Busybox Setings->Instalation Options->(./instal) BusyBox instalation prefix,修改其值為/mnt/sysroot。
3. Don’t use /usr (why?) 

#make
#make instal

安裝後的文件均位於/mnt/sysroot目錄中;但為了創建rootfs,並實現讓其啟動以後將真正的文件系統切換至目標系統分區上的rootfs,您還需要複製一份剛安裝在/mnt/sysroot下的busybox至另一個目錄,以實現與真正的根文件系統分開製作。我們這裡選擇使用/mnt/temp目錄;

#mkdir -pv /mnt/temp
#cp -r /mnt/sysroot/* /mnt/temp

 

四、製作根文件系統 (採 initramfs 方式)

#cd /mnt/temp
1. 建立 rootfs:
# mkdir -pv proc sys etc/init.d tmp dev mnt/sysroot

2. 創建兩個必要的設備文件:
#mknod dev/console c 5 1
#mknod dev/nul c 1 3

3. 為rootfs製作init程序,此程序的主要任務是實現rootfs的切換,因此,可以以腳本的方式來實現它:

#rm linuxrc ( initrd方式使用 linuxrc, initramfs方式使用init )
#vim init

添加如下內容:

#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
# mdev –s 是busybox提供的功能之一,用於探測dev下的所有設備文件和內核映射文件proc
mdev –s
mount -t ext3 /dev/hda2 /mnt/sysroot
exec switch_root /mnt/sysroot /init

# switch_root moves already mounted /proc, /dev and /sys to newroot and makes newroot the new root filesystem and starts init process.

給此腳本執行權限:
#chmod +x init

4、製作rootfs

#find . | cpio -quiet -H newc -o | gzip -9 -n > /mnt/boot/rootfs.cpio.gz

參考文件 :
1. 深入理解 Linux 2.6 的 initramfs 機制
2. ramfs, rootfs and initramfs by Rob Landley

 

五、建立真正的根文件系統

#cd /mnt/sysroot

1、建立rootfs:
#mkdir -pv proc sys etc/init.d tmp dev boot var/log lib

2、創建兩個必要的設備文件:
#mknod dev/console c 5 1
#mknod dev/nul c 1 3

3、建立系統初始化腳本文件
#vim etc/init.d/rcS

添加如下內容:

#!/bin/sh
echo -e "Welcome to \033[31mToyLinux\033[0m\n"
echo -e "Mounting the filesystem .[\033[32mOK\033[0m ]"
mount -t proc proc /proc
mount -t sysfs sysfs /sys
echo -e "Creating the files of device .[\033[32mOK\033[0m ]"
mdev -s
echo -e "Mounting the filesystem .[\033[32mOK\033[0m ]"
mount -a
echo -e "Remounting the root filesystem .[\033[32mOK\033[0m ]"
mount -o remount,rw /
echo -e "Starting the log daemon .[\033[32mOK\033[0m ]"
syslogd
klogd
echo -e "Configuring loopback interface .[\033[32mOK\033[0m ]"
ifconfig lo 127.0.0.1/24
#END

而後讓此腳本具有執行權限:
#chmod +x etc/init.d/rcS

4、配置init及其所需要initab文件

#cd /mnt/sysroot
#mv linuxrc init
#vim etc/initab

添加如下內容:
::sysinit:/etc/init.d/rcS
console::respawn:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

5、為系統準備一個「文件系統表」配置文件/etc/fstab

#vim etc/fstab

添加如下內容:
/dev/hda2    /          ext3     defaults  1 1
sysfs           /sys    sysfs   defaults  0 0
proc            /proc   proc     defaults  0 0
/dev/hda1   /boot    ext3     defaults  0 0

6、由於在rcS文件中啟動了日誌進程,因此系統在運行中會產生大量日誌並將其顯示於控制台;這將會經常性的打斷正在進行的工作,為了避免這種情況,我們這裡為日誌進程建立配置 文件,為其指定將日誌發送至/var/log/messages文件;

#vim etc/syslog.conf

添加如下一行:
*.info /var/log/messages

 

六、好了,至此一個簡易的基於內存運行的小系統已經構建出來了,我們接下來為此系統創建所需的引導程序

#grub-instal -root-directory=/mnt/boot /dev/hda

說明:此處的/dev/hda為目標系統所在的那塊新磁盤;

接下來為grub建立配置文件:
#vim /mnt/boot/grub/grub.conf
添加類似如下內容:
default 0
timeout 3
color light-green/black light-magenta/black
title ToyLinux(2.6.34.1)
root(hd0,0)
kernel /bzImage ro root=/dev/hda2 quiet
initrd /rootfs.cpio.gz

接下來將此塊硬盤接入一個新的主機(這裡使用的是虛擬機),啟動一下並測試使用。

 

七、為新構建的ToyLinux啟用虛擬控制台

這個可以通過宿主機來實現,也可以直接啟動剛構建成功的小Linux進行配置。我們這裡採用通 過宿主機的方式(重新啟動宿主機):
#cd /mnt/sysroot

將 etc/initab文件改為如下內容:
::sysinit:/etc/init.d/rcS
ty1::askfirst:/bin/sh
ty2::askfirst:/bin/sh
ty3::askfirst:/bin/sh
ty4::askfirst:/bin/sh
ty5::askfirst:/bin/sh
ty6::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

好了,接下來就可以測試驗這六個虛擬控制台的使用了。

 

八、儘管上述第七步已經實現了虛擬控制台,但其仍是直接進入系統,且系統沒有用戶帳號等 安全設施,這將不利於系統的安全性。因此,接下來的這步實現為系統添加用戶帳號(這裡仍 然基於宿主機實現)。

1、為目標主機建立passwd帳號文件
#cd /mnt/sysroot
#vim etc/passwd

添加如下內容:
root:x:0:0::/root:/bin/sh

接下來為root用戶建立「家」目錄:
#mkdir root

2、為目標主機建立group帳號文件
#vim etc/group

添加如下內容:
root:x:0:

3、為目標主機建立shadow影子口令文件,這裡採用直接複製宿主機的shadow文件中關於root 口令行的行來實現
#grep "^root"/etc/shadow >etc/shadow

註:等目標主機啟動時,root用戶的口令也是宿主機的root用戶的口令。

4、將 etc/initab文件改為如下內容:
::sysinit:/etc/init.d/rcS
::respawn:/sbin/gety 38400 ty1
::respawn:/sbin/gety 38400 ty2
::respawn:/sbin/gety 38400 ty3
::respawn:/sbin/gety 38400 ty4
::respawn:/sbin/gety 38400 ty5
::respawn:/sbin/gety 38400 ty6
::shutdown:/bin/umount -a -r
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

好了,接下來就可以重新啟動目標主機進行驗正了。

 

九、在系統登錄時提供banner信息

這個可以通過宿主機來實現,也可以直接在目標主機上進行配置。這裡採用直接在目標主機上 配置的方式:

#vi /etc/issue

添加如下內容:

Welcome to ToyLinux

註:這裡的內容可以根據你的需要進行修改。

 

十、在系統啟動時為系統提供主機名稱

這個可以通過宿主機來實現,也可以直接在目標主機上進行配置。這裡採用直接在目標主機上 配置的方式:

1、創建保存主機名稱的配置文件
#mkdir /etc/sysconfig
#vi /etc/sysconfig/network

添加如下內容:
HOSTNAME=marion.example.com

2、編輯系統初始化腳本,實現開機過程中設定主機名稱
#vi /etc/init.d/rcS

在文件尾部添加如下行:
HOSTNAME=
[-r/etc/sysconfig/network]&&source/etc/sysconfig/network
[-z${HOSTNAME}]&& HOSTNAME="localhost"
[-x/bin/hostname]&&/bin/hostname ${HOSTNAME}
unset HOSTNAME

 

十一、移植宿主機的bash至目標主機,以實現在目標主機上使用bash 1、在宿主機上查看bash所依賴的庫文件件,並將這些庫文件複製到目標系統

#cd /mnt/sysroot
#ldd /bin/bash(其顯示可能類似如下所示:)
linux-gate.so.1=> (0x003c0000)
libtermcap.so.2=>/lib/libtermcap.so.2(0x00aa6000)
libdl.so.2=>/lib/libdl.so.2(0x00604000)
libc.so.6=>/lib/libc.so.6(0x008c8000)
/lib/ld-linux.so.2(0x00bf8000)

2、此時,我們需要把除了第一行顯示的以外的餘下的所有庫文件複製到目標主機的lib目錄 中:
#cp /lib/libtermcap.so.2 lib/
#cp /lib/libdl.so.2 lib/
#cp /lib/libc.so.6 lib/
#cp /lib/ld-linux.so.2 lib/

3、而後再把bash程序複製到目標主機的bin目錄中即可:
#cp/bin/bashbin/

 

十二、設置root用戶的默認shel為/bin/bash,並為其定義常用環境變量(本過程在目標主機上 直接實現)

1、新建/etc/shels文件,標明當前系統所用可用shel類型:
#vi /etc/shells

添加如下內容:
/bin/sh
/bin/bash

2、編輯/etc/passwd,設置root用戶的默認shell為/bin/bash
3、編輯/root/.bash_profile,定義PATH,PS1等環境變量
#vim /root/.bash_profile

添加如下內容:
PS1='[\u@\h\W]\$'
HISTSIZE=100
PATH=$PATH:/$HOME/bin
export PS1 HISTSIZE PATH

 

十三、定義名稱解析方式 完成上述第十二步以後,用戶的shel提示符中的用戶名很可能顯示為:I have no name!

這個主要是沒有配置名稱解析服務造成的。本步驟則來嘗試解決此問題,並嘗試實現為主機名稱 解析定義其解析方式。

提示:本步驟需要在宿主機上實現

1、為名稱解析服務複製必要的庫文件:
#cd /mnt/sysroot
#cp /lib/libnss_files* lib/
#cp /lib/libnss_dns* lib/

2、為目標主機建立名稱解析文件nsswitch.conf
#vim etc/nsswitch.conf

添加如下內容:
passwd: files
group: files
shadow: files
hosts: files dns

3、為主機名稱解析建立etc/hosts文件,可根據需要添加其內容
#vim etc/hosts

添加如下內容(如果本機有IP地址,也可以在此配置):
127.0.0.1 localhost

 

十四、為目標主機提供一個web服務器

嵌入式系統上可用的輕量級web服務器有如Boa,thttpd,lighttpd,shttpd等。我們這裡選用 thttpd,且只提供簡單的web服務。

1、在宿主機上編譯thttpd
#tar -zxvf thttpd-2.25b.tar.gz
#cd thttpd-2.25b
#./configure
#make

2、複製編譯好的thttpd至目標主機
#mkdir -pv /mnt/sysroot/usr/local/sbin
#cp -p thttpd /mnt/sysroot/usr/local/sbin/

3、複製thttpd依賴的庫文件至目標主機
#ldd thttpd
linux-gate.so.1=> (0x00e75000)
libcrypt.so.1=>/lib/libcrypt.so.1(0x04f3a000)
libc.so.6=>/lib/libc.so.6(0x00931000)
/lib/ld-linux.so.2(0x0090e000)

請確保以上所依賴的庫文件均複製到了/mnt/sysroot/lib目錄中。

4、為目標主機上運行thtpd進程建立一個有效用戶帳號(此用戶不需要「家」目錄)

#echo"www:x:1000:1000:www:/bin/bash">>/mnt/sysroot/etc/passwd
#echo"www:x:1000:">>/mnt/sysroot/etc/group

5、接下來啟動目標主機系統,登錄後創建網站目錄,並創建一個測試頁面
#mkdir /var/www/html
#echo'<h1>Atestpage.</h1>'>/var/www/html/index.html

而後啟動thtpd進程:
#/usr/local/sbin/thttpd -uwww-dd/var/www/html-l/var/log/thttpd.log&

接下來就可以進行測試訪問了。請確保此時目標主機有合適的IP地址。

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.