重启工具链
与 LFS 的标准做法不同,本文为了尽可能摆脱宿主系统的影响,做完工具链之后不是chroot进入虚根环境,而是做一些必要的准备工作,然后重新启动计算机,进入一个完全与宿主系统无关的工具链环境,再继续完成目标系统的构建。
创建基础目录结构、必需的符号连接与文件、存储随机数种子、用户和组([注意]pgsql属于www组,root的密码是"123"):
[提示]如果现在就将 mtab 指向 /proc/mounts 的话,Coreutils 测试程序会将 /dev/root 挂载到 tests/rm/one-file-system.tmp/ 下的某个目录中,从而导致无法删除Coreutils 的编译目录。
mkdir $LFS/{boot,bin,etc,lib,dev/{pts,shm},share,root,usr/{bin,lib},var/log,www,data,proc} && ln -sf /dev/shm/tmp $LFS/tmp && ln -sf /dev/shm/run $LFS/var/run && touch $LFS/etc/mtab $LFS/var/log/{btmp,lastlog,wtmp} && ln -sf bash $LFS/bin/sh && cp /www/bin/{bash,echo,mount} $LFS/bin/ && ln -sf /www/bin/{env,perl} $LFS/usr/bin/ && ln -sf /www/lib/libgcc_s.so.1 $LFS/usr/lib/ && dd if=/dev/urandom of=$LFS/var/random-seed bs=8k count=1 && dd if=/dev/urandom of=$LFS/var/urandom-seed bs=8k count=1 && echo 'root:$1$/y21SFaU$uQ0nsncCJcYjrfgJ9qvA31:0:0:SuperUser:/root:/bin/bash httpd:*:1001:1000:httpdDaemon:/www:/bin/false pgsql:*:1002:1000:pgsqlDaemon:/data:/bin/false sshd:*:3001:3000:sshdPrivSep:/share/empty:/bin/false' > $LFS/etc/passwd && echo 'root::0: www::1000: sshd::3000:' > $LFS/etc/group &&
Linux 中的设备有2种类型:字符设备(无缓冲且只能顺序存取)、块设备(有缓冲且可以随机存取)。每个字符设备和块设备都必须有主、次设备号,主设备号相同的设备是同类设备(使用同一个驱动程序)。这些设备中,有些设备是对实际存在的物理硬件的抽象,而有些设备则是内核自身提供的功能(不依赖于特定的物理硬件,又称为"虚拟设备")。每个设备在 /dev 目录下都有一个对应的文件(节点)。可以通过 cat /proc/devices 命令查看当前已经加载的设备驱动程序的主设备号。内核能够识别的所有设备都记录在源码树下的 Documentation/devices.txt 文件中。在 /dev 目录下除了字符设备和块设备节点之外还通常还会存在:FIFO管道、Socket、软/硬连接、目录。这些东西没有主/次设备号。
由于本文不打算使用 Udev ,因此这里手动创建所有设备。
# mkfifo -m 600 $LFS/dev/initctl && mknod -m 666 $LFS/dev/null c 1 3 && mknod -m 666 $LFS/dev/zero c 1 5 && mknod -m 666 $LFS/dev/full c 1 7 && mknod -m 666 $LFS/dev/random c 1 8 && mknod -m 666 $LFS/dev/urandom c 1 9 && mknod -m 666 $LFS/dev/tty0 c 4 0 && mknod -m 666 $LFS/dev/tty1 c 4 1 && mknod -m 666 $LFS/dev/tty2 c 4 2 && mknod -m 666 $LFS/dev/tty3 c 4 3 && mknod -m 666 $LFS/dev/tty c 5 0 && mknod -m 666 $LFS/dev/console c 5 1 && mknod -m 666 $LFS/dev/ptmx c 5 2 && mknod -m 666 $LFS/dev/sda b 8 0 && mknod -m 666 $LFS/dev/sda1 b 8 1 && mknod -m 666 $LFS/dev/sda2 b 8 2 && mknod -m 666 $LFS/dev/sda3 b 8 3 && mknod -m 666 $LFS/dev/sda4 b 8 4 && mknod -m 666 $LFS/dev/sda5 b 8 5 && mknod -m 666 $LFS/dev/sda6 b 8 6 && mknod -m 666 $LFS/dev/sda7 b 8 7 && mknod -m 666 $LFS/dev/sda8 b 8 8 && mknod -m 666 $LFS/dev/sda9 b 8 9 && mknod -m 666 $LFS/dev/rtc c 10 135 && mknod -m 666 $LFS/dev/hpet c 10 228 && ln -sf /proc/self/fd $LFS/dev/fd && ln -sf /proc/self/fd/0 $LFS/dev/stdin && ln -sf /proc/self/fd/1 $LFS/dev/stdout && ln -sf /proc/self/fd/2 $LFS/dev/stderr && ln -sf /proc/kcore $LFS/dev/core &&
由于安装 Iana-Etc 包之后将会产生巨大的 /etc/services 文件,从而对性能有不良影响(比如 getservbyname() 函数将会变慢),因此本文并未安装 Iana-Etc 包。但是 Prel 的 ext/IO/ 与 lib/Net/ 目录下的几个测试套件依赖于 Iana-Etc 包。因此为了测试的完整性,先从宿主系统复制临时的 /etc/{protocols,services} 文件,然后在 Perl 测试完毕之后再删除它们。此外,好几个 Perl 测试项目都需要 /etc/hosts 文件来解析 localhost 的名称("miniLAPP"),为了顺利运行测试套件,这里也提前创建它:
cp /etc/{protocols,services} $LFS/etc/ && echo '127.0.0.1 localhost miniLAPP' > $LFS/etc/hosts &&
设置Bash启动脚本,一方面是为了做编译前的准备,另一方面也是为了简化了关机后的状态回复工作。[提示]"umask 000"会导致 Coreutils 测试失败。TERM环境变量将由系统自动设置。
echo "set +h umask 022 export HOME=/root PS1='$PS1' TZ=$TZ SRC=/data export PATH=/bin:/usr/bin:/www/bin export CFLAGS='$CFLAGS' LDFLAGS='$LDFLAGS' kLDFLAGS='$kLDFLAGS' alias make='make -j1' mkdir='mkdir -p' patch='patch -p1 -i' mv='mv -f' cp='cp -pf' rm='rm -fr' echo miniLAPP > /proc/sys/kernel/hostname mkdir -m 1777 /dev/shm/{tmp,run,pg_socket,php_session} touch /var/run/utmp cd \$SRC" > $LFS/etc/profile &&
编写启动脚本。
echo '#!/bin/bash /bin/mount -t proc proc /proc && /bin/mount -t tmpfs shm /dev/shm && /bin/mount -t devpts devpts /dev/pts && /bin/mount -t ext2 /dev/sda1 /boot && /bin/mount -t xfs /dev/sda5 /usr && /bin/mount -t xfs /dev/sda6 /root && /bin/mount -t xfs /dev/sda7 /var && /bin/mount -t xfs /dev/sda8 /www && /bin/mount -t xfs /dev/sda9 /data && /www/bin/ip -4 link set lo txqueuelen 0 && /www/bin/ip -4 link set eth0 txqueuelen 4000 && /www/bin/ip -4 link set lo mtu 16436 && /www/bin/ip -4 link set eth0 mtu 1500 && /www/bin/ip -4 addr add 127.0.0.1/8 scope host dev lo valid_lft forever preferred_lft forever && /www/bin/ip -4 addr add 192.168.10.33/24 broadcast 192.168.10.255 scope global dev eth0 valid_lft forever preferred_lft forever && /www/bin/ip -4 link set lo up && /www/bin/ip -4 link set eth0 up && /www/bin/ip -4 route add unicast default via 192.168.10.250 dev eth0 && /bin/bash --login +h' > $LFS/bin/tmpinit && chmod 755 $LFS/bin/tmpinit &&
由于GRUB-0.97年久失修,毛病多多,因此这里使用咱们中国人主导开发的GRUB4DOS。
cp $SRC/grldr $LFS/boot/ && echo 'kernel (hd0,0)/bzImage root=0802 rootfstype=xfs rw init=/bin/tmpinit panic=30' > $LFS/boot/menu.lst && chmod +x $SRC/bootlace.com && $SRC/bootlace.com --no-backup-mbr --mbr-disable-floppy --mbr-disable-osbr --boot-prevmbr-last /dev/sda &&
接下来有两个分支可选,推荐使用默认的分支㈠,因为分支㈡未经本文作者严格测试,可能会存在某些问题。
分支㈠[关机]
关机前的准备(如果没有启动ssh就省略相应的命令):
/etc/rc.d/init.d/sshd stop && rm ~/.bash* && sync && exit
必须确保一直 exit 到出现"Press Enter to activate this virtual console..."为止,然后再按回车键重新登陆并按下列步骤关机:
cd / && rm -f /etc/mtab && umount /dev/sda{9,8,7,6,5,1,2} && poweroff
OK! 下次重新开机的时候将BIOS中的启动盘调整为硬盘,即可继续进行下面"编译最终系统"的工作。
分支㈡[chroot]
为了方便期望在编译最终系统的过程中也能使用ssh的读者,这里也介绍一下传统的chroot方法。需要说明的是,由于此分支的方法不能完全摆脱宿主系统的影响,所以本文不推荐使用。仅供那些贪图copy/paste便利的玩家参考和测试。
mount -t devpts devpts $LFS/dev/pts && mount -t tmpfs shm $LFS/dev/shm && mount -t proc proc $LFS/proc && chroot $LFS /usr/bin/env -i TERM=$TERM /bin/bash --login +h