重启工具链

优质
小牛编辑
122浏览
2023-12-01

与 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