NakanoMiku39
Articles17
Tags31
Categories3

Categories

Archive

构造基于x86_64的LFS(4)

构造基于x86_64的LFS(4)

继续构造LFS,从系统配置开始

系统配置

现在需要配置内核引导过程
一定一定一定注意当前是否处于chroot环境

LFS-Bootscripts

解压LFS-Bootscripts

1
2
3
cd /sources/
tar -xf lfs-bootscripts-20240825.tar.xz
cd lfs-bootscripts-20240825

安装软件包

1
make install

之前安装了Udev程序,现在需要进行一些配置来管理设备,生成Udev初始规则

1
bash /usr/lib/udev/init-net-rules.sh

检查文件 /etc/udev/rules.d/70-persistent-net.rules,确认网络设备与命名的对应关系

1
cat /etc/udev/rules.d/70-persistent-net.rules

记住NAME

1
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="e8:9c:25:97:d0:3b", ATTR{dev_id}=="0x0", ATTR{type}=="1", NAME="eno1"

现在开始网络配置,需要为网络接口创建一个静态IP配置,上面已经记录了接口的名字,也就是eno1(NAME=”eno1”),所以配置如下

1
2
3
4
5
6
7
8
9
10
cd /etc/sysconfig/
cat > ifconfig.eno1 << "EOF"
ONBOOT=yes
IFACE=eno1
SERVICE=ipv4-static
IP=192.168.1.2
GATEWAY=192.168.1.1
PREFIX=24
BROADCAST=192.168.1.255
EOF

现在要配置DNS解析,配置如下

1
2
3
4
5
6
7
8
cat > /etc/resolv.conf << "EOF"
# Begin /etc/resolv.conf

8.8.8.8
8.8.4.4

# End /etc/resolv.conf
EOF

配置系统主机名

1
echo "LFS" > /etc/hostname

配置IP地址

1
2
3
4
5
6
7
8
9
10
cat > /etc/hosts << "EOF"
# Begin /etc/hosts

127.0.0.1 localhost.localdomain localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

# End /etc/hosts
EOF

现在配置SysVinit,首先创建/etc/inittab文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cat > /etc/inittab << "EOF"
# Begin /etc/inittab

id:3:initdefault:

si::sysinit:/etc/rc.d/init.d/rc S

l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

su:S06:once:/sbin/sulogin
s1:1:respawn:/sbin/sulogin

1:2345:respawn:/sbin/agetty --noclear tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600

# End /etc/inittab
EOF

配置系统时钟,先检查硬件时钟是否被设置成UTC,如果有则下面的UTC=1,否则UTC=0

1
2
3
4
5
6
7
8
9
10
11
12
13
hwclock --localtime --show

cat > /etc/sysconfig/clock << "EOF"
# Begin /etc/sysconfig/clock

UTC=1

# Set this to any options you might need to give to hwclock,
# such as machine hardware clock type for Alphas.
CLOCKPARAMS=

# End /etc/sysconfig/clock
EOF

下面配置console,这里采用手册提供的第一个例子作为配置

1
2
3
4
5
6
7
8
cat > /etc/sysconfig/console << "EOF"
# Begin /etc/sysconfig/console

UNICODE="1"
FONT="Lat2-Terminus16"

# End /etc/sysconfig/console
EOF

现在配置系统locale,可以使用下面命令列出Glibc支持的所有locale

1
locale -a

配置locale,在此之前需要检查是否支持选择的locale

1
2
3
4
LC_ALL=zh_CN locale language
LC_ALL=zh_CN locale charmap
LC_ALL=zh_CN locale int_curr_symbol
LC_ALL=zh_CN locale int_prefix

如果其中有以下输出,说明该locale没有被安装,或者Glibc不支持

1
locale: Cannot set LC_* to default locale: No such file or directory

创建/etc/profile以设定locale

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat > /etc/profile << "EOF"
# Begin /etc/profile

for i in $(locale); do
unset ${i%=*}
done

if [[ "$TERM" = linux ]]; then
export LANG=C.UTF-8
else
export LANG=zh_CN.UTF-8
fi

# End /etc/profile
EOF

创建/etc/inputrc文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
cat > /etc/inputrc << "EOF"
# Begin /etc/inputrc
# Modified by Chris Lynn <roryo@roryo.dynup.net>

# Allow the command prompt to wrap to the next line
set horizontal-scroll-mode Off

# Enable 8-bit input
set meta-flag On
set input-meta On

# Turns off 8th bit stripping
set convert-meta Off

# Keep the 8th bit for display
set output-meta On

# none, visible or audible
set bell-style none

# All of the following map the escape sequence of the value
# contained in the 1st argument to the readline specific functions
"\eOd": backward-word
"\eOc": forward-word

# for linux console
"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[3~": delete-char
"\e[2~": quoted-insert

# for xterm
"\eOH": beginning-of-line
"\eOF": end-of-line

# for Konsole
"\e[H": beginning-of-line
"\e[F": end-of-line

# End /etc/inputrc
EOF

创建/etc/shells文件

1
2
3
4
5
6
7
8
cat > /etc/shells << "EOF"
# Begin /etc/shells

/bin/sh
/bin/bash

# End /etc/shells
EOF

使 LFS 系统可引导

创建/etc/fstab文件,这里涉及到文件系统的“名字”,我选择用UUID,可以通过blkid命令来查看文件系统的UUID,然后将值填入/etc/fstab

1
blkid

输出如下,其中/dev/sdc1是当前LFS分区所在的文件系统上,对应的UUID就是315ffc52-a533-4a9d-954a-a1d6c891a25f

1
2
3
4
5
6
7
/dev/nvme0n1p3: UUID="a9642acd-3e82-459c-b7ec-f0f846a5485d" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="e697a942-04c6-4f27-9514-ff7496ce1fe9"
/dev/nvme0n1p1: UUID="270E-0D67" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="364861e4-27a5-4c6c-9ff3-45eb29888856"
/dev/nvme0n1p2: UUID="bc12805b-5399-46f8-94af-4ba4f1884420" TYPE="swap" PARTUUID="b90ad2a6-f3bb-4374-b9cc-88cd70e5ad57"
/dev/sdc1: UUID="315ffc52-a533-4a9d-954a-a1d6c891a25f" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="0127e901-01"
/dev/sdb1: UUID="bc14ec76-1e31-bdf8-b20b-4d19768c23eb" UUID_SUB="84c7d62a-420b-232d-5625-af84e9ad8d93" LABEL="debian:0" TYPE="linux_raid_member" PARTUUID="8a56aa87-01"
/dev/md0: UUID="ee5405d0-c592-41cc-946c-d25e8c99fa3a" BLOCK_SIZE="4096" TYPE="ext4"
/dev/sda1: UUID="bc14ec76-1e31-bdf8-b20b-4d19768c23eb" UUID_SUB="acfe69f5-9f53-56b8-cf6b-bd4cba4f4c5d" LABEL="debian:0" TYPE="linux_raid_member" PARTUUID="37f959a3-01"

修改文件系统和类型,因为之前没有制作交换分区,故这里注释掉swap,而这里使用了UUID,所以需要使用UUID=文件系统的UUID的格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat > /etc/fstab << "EOF"
# Begin /etc/fstab

UUID=315ffc52-a533-4a9d-954a-a1d6c891a25f / ext4 defaults 1 1
# /dev/nvme0n1p2 swap swap pri=1 0 0
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /run tmpfs defaults 0 0
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0
tmpfs /dev/shm tmpfs nosuid,nodev 0 0
cgroup2 /sys/fs/cgroup cgroup2 nosuid,noexec,nodev 0 0

# End /etc/fstab
EOF

现在可以安装内核了,首先准备编译内核

1
2
3
4
5
cd /sources/
rm -rf linux-6.10.5
tar -xf linux-6.10.5.tar.xz
cd linux-6.10.5
make mrproper

配置内核选项

1
make menuconfig

我的配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
General setup --->
[ ] Compile the kernel with warnings as errors [WERROR]
CPU/Task time and stats accounting --->
[*] Pressure stall information tracking [PSI]
[ ] Require boot parameter to enable pressure stall information tracking
... [PSI_DEFAULT_DISABLED]
< > Enable kernel headers through /sys/kernel/kheaders.tar.xz [IKHEADERS]
[*] Control Group support ---> [CGROUPS]
[*] Memory controller [MEMCG]
[ ] Configure standard kernel features (expert users) ---> [EXPERT]

Processor type and features --->
[*] Build a relocatable kernel [RELOCATABLE]
[*] Randomize the address of the kernel image (KASLR) [RANDOMIZE_BASE]
[*] Support x2apic [X86_X2APIC]

General architecture-dependent options --->
[*] Stack Protector buffer overflow detection [STACKPROTECTOR]
[*] Strong Stack Protector [STACKPROTECTOR_STRONG]

Device Drivers --->
Generic Driver Options --->
[ ] Support for uevent helper [UEVENT_HELPER]
[*] Maintain a devtmpfs filesystem to mount at /dev [DEVTMPFS]
[*] Automount devtmpfs at /dev, after the kernel mounted the rootfs
... [DEVTMPFS_MOUNT]
Graphics support --->
< /*/M> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) --->
... [DRM]
# If [DRM] is selected as * or M, this must be selected:
[ /*] Enable legacy fbdev support for your modesetting driver
... [DRM_FBDEV_EMULATION]
Console display driver support --->
# If [DRM] is selected as * or M, this must be selected:
[ /*] Framebuffer Console support [FRAMEBUFFER_CONSOLE]

[*] PCI support ---> [PCI]
[*] Message Signaled Interrupts (MSI and MSI-X) [PCI_MSI]
[*] IOMMU Hardware Support ---> [IOMMU_SUPPORT]
[*] Support for Interrupt Remapping [IRQ_REMAP]

现在开始编译内核

1
make

编译完成后复制内核映像到/boot目录下

1
cp -iv arch/x86/boot/bzImage /boot/vmlinuz-6.10.5-lfs-12.2

System.map 是内核符号文件,它将内核 API 的每个函数入口点和运行时数据结构映射到它们的地址。它被用于调查分析内核可能出现的问题。执行以下命令安装该文件

1
cp -iv System.map /boot/System.map-6.10.5

保留一份内核配置文件供参考

1
cp -iv .config /boot/config-6.10.5

安装 Linux 内核文档

1
cp -r Documentation -T /usr/share/doc/linux-6.10.5

保留内核源码树

1
chown -R 0:0 .

配置 Linux 内核模块加载顺序,创建文件 /etc/modprobe.d/usb.conf

1
2
3
4
5
6
7
8
9
install -v -m755 -d /etc/modprobe.d
cat > /etc/modprobe.d/usb.conf << "EOF"
# Begin /etc/modprobe.d/usb.conf

install ohci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe -i ohci_hcd ; true
install uhci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe -i uhci_hcd ; true

# End /etc/modprobe.d/usb.conf
EOF

安装GRUB

1
grub-install /dev/sdc  --target i386-pc

因为是在U盘中制作LFS,所以需要进行额外步骤,也就是安装initrd
首先安装cpio,因为mkinitramfs依赖于cpio

1
2
3
4
5
6
7
8
9
10
11
exit
cd $LFS/sources/
wget https://ftp.gnu.org/gnu/cpio/cpio-2.15.tar.bz2
chroot "$LFS" /usr/bin/env -i \
HOME=/root \
TERM="$TERM" \
PS1='(lfs chroot) \u:\w\$ ' \
PATH=/usr/bin:/usr/sbin \
MAKEFLAGS="-j$(nproc)" \
TESTSUITEFLAGS="-j$(nproc)" \
/bin/bash --login

cpio

解压cpio

1
2
3
cd /sources
tar -xf cpio-2.15.tar.bz2
cd cpio-2.15

准备并编译cpio

1
2
3
4
5
6
7
./configure --prefix=/usr \
--enable-mt \
--with-rmt=/usr/libexec/rmt &&
make &&
makeinfo --html -o doc/html doc/cpio.texi &&
makeinfo --html --no-split -o doc/cpio.html doc/cpio.texi &&
makeinfo --plaintext -o doc/cpio.txt doc/cpio.texi

测试编译结果

1
make check

安装软件包

1
2
3
4
5
6
make install &&
install -v -m755 -d /usr/share/doc/cpio-2.15/html &&
install -v -m644 doc/html/* \
/usr/share/doc/cpio-2.15/html &&
install -v -m644 doc/cpio.{html,txt} \
/usr/share/doc/cpio-2.15

现在需要创建两个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
cat > /usr/sbin/mkinitramfs << "EOF"
#!/bin/bash
# This file based in part on the mkinitramfs script for the LFS LiveCD
# written by Alexander E. Patrakov and Jeremy Huntwork.

copy()
{
local file

if [ "$2" = "lib" ]; then
file=$(PATH=/usr/lib type -p $1)
else
file=$(type -p $1)
fi

if [ -n "$file" ] ; then
cp $file $WDIR/usr/$2
else
echo "Missing required file: $1 for directory $2"
rm -rf $WDIR
exit 1
fi
}

if [ -z $1 ] ; then
INITRAMFS_FILE=initrd.img-no-kmods
else
KERNEL_VERSION=$1
INITRAMFS_FILE=initrd.img-$KERNEL_VERSION
fi

if [ -n "$KERNEL_VERSION" ] && [ ! -d "/usr/lib/modules/$1" ] ; then
echo "No modules directory named $1"
exit 1
fi

printf "Creating $INITRAMFS_FILE... "

binfiles="sh cat cp dd killall ls mkdir mknod mount "
binfiles="$binfiles umount sed sleep ln rm uname"
binfiles="$binfiles readlink basename"

# Systemd installs udevadm in /bin. Other udev implementations have it in /sbin
if [ -x /usr/bin/udevadm ] ; then binfiles="$binfiles udevadm"; fi

sbinfiles="modprobe blkid switch_root"

# Optional files and locations
for f in mdadm mdmon udevd udevadm; do
if [ -x /usr/sbin/$f ] ; then sbinfiles="$sbinfiles $f"; fi
done

# Add lvm if present (cannot be done with the others because it
# also needs dmsetup
if [ -x /usr/sbin/lvm ] ; then sbinfiles="$sbinfiles lvm dmsetup"; fi

unsorted=$(mktemp /tmp/unsorted.XXXXXXXXXX)

DATADIR=/usr/share/mkinitramfs
INITIN=init.in

# Create a temporary working directory
WDIR=$(mktemp -d /tmp/initrd-work.XXXXXXXXXX)

# Create base directory structure
mkdir -p $WDIR/{dev,run,sys,proc,usr/{bin,lib/{firmware,modules},sbin}}
mkdir -p $WDIR/etc/{modprobe.d,udev/rules.d}
touch $WDIR/etc/modprobe.d/modprobe.conf
ln -s usr/bin $WDIR/bin
ln -s usr/lib $WDIR/lib
ln -s usr/sbin $WDIR/sbin
ln -s lib $WDIR/lib64

# Create necessary device nodes
mknod -m 640 $WDIR/dev/console c 5 1
mknod -m 664 $WDIR/dev/null c 1 3

# Install the udev configuration files
if [ -f /etc/udev/udev.conf ]; then
cp /etc/udev/udev.conf $WDIR/etc/udev/udev.conf
fi

for file in $(find /etc/udev/rules.d/ -type f) ; do
cp $file $WDIR/etc/udev/rules.d
done

# Install any firmware present
cp -a /usr/lib/firmware $WDIR/usr/lib

# Copy the RAID configuration file if present
if [ -f /etc/mdadm.conf ] ; then
cp /etc/mdadm.conf $WDIR/etc
fi

# Install the init file
install -m0755 $DATADIR/$INITIN $WDIR/init

if [ -n "$KERNEL_VERSION" ] ; then
if [ -x /usr/bin/kmod ] ; then
binfiles="$binfiles kmod"
else
binfiles="$binfiles lsmod"
sbinfiles="$sbinfiles insmod"
fi
fi

# Install basic binaries
for f in $binfiles ; do
ldd /usr/bin/$f | sed "s/\t//" | cut -d " " -f1 >> $unsorted
copy /usr/bin/$f bin
done

for f in $sbinfiles ; do
ldd /usr/sbin/$f | sed "s/\t//" | cut -d " " -f1 >> $unsorted
copy $f sbin
done

# Add udevd libraries if not in /usr/sbin
if [ -x /usr/lib/udev/udevd ] ; then
ldd /usr/lib/udev/udevd | sed "s/\t//" | cut -d " " -f1 >> $unsorted
elif [ -x /usr/lib/systemd/systemd-udevd ] ; then
ldd /usr/lib/systemd/systemd-udevd | sed "s/\t//" | cut -d " " -f1 >> $unsorted
fi

# Add module symlinks if appropriate
if [ -n "$KERNEL_VERSION" ] && [ -x /usr/bin/kmod ] ; then
ln -s kmod $WDIR/usr/bin/lsmod
ln -s kmod $WDIR/usr/bin/insmod
fi

# Add lvm symlinks if appropriate
# Also copy the lvm.conf file
if [ -x /usr/sbin/lvm ] ; then
ln -s lvm $WDIR/usr/sbin/lvchange
ln -s lvm $WDIR/usr/sbin/lvrename
ln -s lvm $WDIR/usr/sbin/lvextend
ln -s lvm $WDIR/usr/sbin/lvcreate
ln -s lvm $WDIR/usr/sbin/lvdisplay
ln -s lvm $WDIR/usr/sbin/lvscan

ln -s lvm $WDIR/usr/sbin/pvchange
ln -s lvm $WDIR/usr/sbin/pvck
ln -s lvm $WDIR/usr/sbin/pvcreate
ln -s lvm $WDIR/usr/sbin/pvdisplay
ln -s lvm $WDIR/usr/sbin/pvscan

ln -s lvm $WDIR/usr/sbin/vgchange
ln -s lvm $WDIR/usr/sbin/vgcreate
ln -s lvm $WDIR/usr/sbin/vgscan
ln -s lvm $WDIR/usr/sbin/vgrename
ln -s lvm $WDIR/usr/sbin/vgck
# Conf file(s)
cp -a /etc/lvm $WDIR/etc
fi

# Install libraries
sort $unsorted | uniq | while read library ; do
# linux-vdso and linux-gate are pseudo libraries and do not correspond to a file
# libsystemd-shared is in /lib/systemd, so it is not found by copy, and
# it is copied below anyway
if [[ "$library" == linux-vdso.so.1 ]] ||
[[ "$library" == linux-gate.so.1 ]] ||
[[ "$library" == libsystemd-shared* ]]; then
continue
fi

copy $library lib
done

if [ -d /usr/lib/udev ]; then
cp -a /usr/lib/udev $WDIR/usr/lib
fi
if [ -d /usr/lib/systemd ]; then
cp -a /usr/lib/systemd $WDIR/usr/lib
fi
if [ -d /usr/lib/elogind ]; then
cp -a /usr/lib/elogind $WDIR/usr/lib
fi

# Install the kernel modules if requested
if [ -n "$KERNEL_VERSION" ]; then
find \
/usr/lib/modules/$KERNEL_VERSION/kernel/{crypto,fs,lib} \
/usr/lib/modules/$KERNEL_VERSION/kernel/drivers/{block,ata,nvme,md,firewire} \
/usr/lib/modules/$KERNEL_VERSION/kernel/drivers/{scsi,message,pcmcia,virtio} \
/usr/lib/modules/$KERNEL_VERSION/kernel/drivers/usb/{host,storage} \
-type f 2> /dev/null | cpio --make-directories -p --quiet $WDIR

cp /usr/lib/modules/$KERNEL_VERSION/modules.{builtin,order} \
$WDIR/usr/lib/modules/$KERNEL_VERSION
if [ -f /usr/lib/modules/$KERNEL_VERSION/modules.builtin.modinfo ]; then
cp /usr/lib/modules/$KERNEL_VERSION/modules.builtin.modinfo \
$WDIR/usr/lib/modules/$KERNEL_VERSION
fi

depmod -b $WDIR $KERNEL_VERSION
fi

( cd $WDIR ; find . | cpio -o -H newc --quiet | gzip -9 ) > $INITRAMFS_FILE

# Prepare early loading of microcode if available
if ls /usr/lib/firmware/intel-ucode/* >/dev/null 2>&1 ||
ls /usr/lib/firmware/amd-ucode/* >/dev/null 2>&1; then

# first empty WDIR to reuse it
rm -r $WDIR/*

DSTDIR=$WDIR/kernel/x86/microcode
mkdir -p $DSTDIR

if [ -d /usr/lib/firmware/amd-ucode ]; then
cat /usr/lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
fi

if [ -d /usr/lib/firmware/intel-ucode ]; then
cat /usr/lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin
fi

( cd $WDIR; find . | cpio -o -H newc --quiet ) > microcode.img
cat microcode.img $INITRAMFS_FILE > tmpfile
mv tmpfile $INITRAMFS_FILE
rm microcode.img
fi

# Remove the temporary directories and files
rm -rf $WDIR $unsorted
printf "done.\n"

EOF

chmod 0755 /usr/sbin/mkinitramfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
mkdir -p /usr/share/mkinitramfs &&
cat > /usr/share/mkinitramfs/init.in << "EOF"
#!/bin/sh

PATH=/usr/bin:/usr/sbin
export PATH

problem()
{
printf "Encountered a problem!\n\nDropping you to a shell.\n\n"
sh
}

no_device()
{
printf "The device %s, which is supposed to contain the\n" $1
printf "root file system, does not exist.\n"
printf "Please fix this problem and exit this shell.\n\n"
}

no_mount()
{
printf "Could not mount device %s\n" $1
printf "Sleeping forever. Please reboot and fix the kernel command line.\n\n"
printf "Maybe the device is formatted with an unsupported file system?\n\n"
printf "Or maybe filesystem type autodetection went wrong, in which case\n"
printf "you should add the rootfstype=... parameter to the kernel command line.\n\n"
printf "Available partitions:\n"
}

do_mount_root()
{
mkdir /.root
[ -n "$rootflags" ] && rootflags="$rootflags,"
rootflags="$rootflags$ro"

case "$root" in
/dev/* ) device=$root ;;
UUID=* ) eval $root; device="/dev/disk/by-uuid/$UUID" ;;
PARTUUID=*) eval $root; device="/dev/disk/by-partuuid/$PARTUUID" ;;
LABEL=* ) eval $root; device="/dev/disk/by-label/$LABEL" ;;
"" ) echo "No root device specified." ; problem ;;
esac

while [ ! -b "$device" ] ; do
no_device $device
problem
done

if ! mount -n -t "$rootfstype" -o "$rootflags" "$device" /.root ; then
no_mount $device
cat /proc/partitions
while true ; do sleep 10000 ; done
else
echo "Successfully mounted device $root"
fi
}

do_try_resume()
{
case "$resume" in
UUID=* ) eval $resume; resume="/dev/disk/by-uuid/$UUID" ;;
LABEL=*) eval $resume; resume="/dev/disk/by-label/$LABEL" ;;
esac

if $noresume || ! [ -b "$resume" ]; then return; fi

ls -lH "$resume" | ( read x x x x maj min x
echo -n ${maj%,}:$min > /sys/power/resume )
}

init=/sbin/init
root=
rootdelay=
rootfstype=auto
ro="ro"
rootflags=
device=
resume=
noresume=false

mount -n -t devtmpfs devtmpfs /dev
mount -n -t proc proc /proc
mount -n -t sysfs sysfs /sys
mount -n -t tmpfs tmpfs /run

read -r cmdline < /proc/cmdline

for param in $cmdline ; do
case $param in
init=* ) init=${param#init=} ;;
root=* ) root=${param#root=} ;;
rootdelay=* ) rootdelay=${param#rootdelay=} ;;
rootfstype=*) rootfstype=${param#rootfstype=} ;;
rootflags=* ) rootflags=${param#rootflags=} ;;
resume=* ) resume=${param#resume=} ;;
noresume ) noresume=true ;;
ro ) ro="ro" ;;
rw ) ro="rw" ;;
esac
done

# udevd location depends on version
if [ -x /sbin/udevd ]; then
UDEVD=/sbin/udevd
elif [ -x /lib/udev/udevd ]; then
UDEVD=/lib/udev/udevd
elif [ -x /lib/systemd/systemd-udevd ]; then
UDEVD=/lib/systemd/systemd-udevd
else
echo "Cannot find udevd nor systemd-udevd"
problem
fi

${UDEVD} --daemon --resolve-names=never
udevadm trigger
udevadm settle

if [ -f /etc/mdadm.conf ] ; then mdadm -As ; fi
if [ -x /sbin/vgchange ] ; then /sbin/vgchange -a y > /dev/null ; fi
if [ -n "$rootdelay" ] ; then sleep "$rootdelay" ; fi

do_try_resume # This function will not return if resuming from disk
do_mount_root

killall -w ${UDEVD##*/}

exec switch_root /.root "$init" "$@"

EOF

现在可以构建initramfs

1
2
cd /boot
mkinitramfs

生成 /boot/grub/grub.cfg,这里需要获取到文件系统的UUID和分区的UUID,前面也已经通过blkid获取到了,其中文件系统的UUID指UUID,分区的UUID指PARTUUID
可以通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat > /boot/grub/grub.cfg << "EOF"
# Begin /boot/grub/grub.cfg
set default=0
set timeout=5

insmod part_gpt
insmod ext2
search --set=root --fs-uuid 315ffc52-a533-4a9d-954a-a1d6c891a25f

menuentry "GNU/Linux, Linux 6.10.5-lfs-12.2" {
linux /boot/vmlinuz-6.10.5-lfs-12.2 root=PARTUUID=0127e901-01 ro rootdelay=5
initrd /boot/initrd.img-no-kmods
}
EOF

收尾工作

创建/etc/lfs-release来定义LFS系统版本

1
echo 12.2 > /etc/lfs-release

后续安装在系统上的软件包可能需要两个描述当前安装的系统的文件,这些软件包可能是二进制包,也可能是需要构建的源代码包。
第一个文件根据 Linux Standards Base (LSB) 的规则描述系统状态。运行命令创建该文件
修改DISTRIB_CODENAME

1
2
3
4
5
6
cat > /etc/lsb-release << "EOF"
DISTRIB_ID="Linux From Scratch"
DISTRIB_RELEASE="12.2"
DISTRIB_CODENAME="Miku"
DISTRIB_DESCRIPTION="Linux From Scratch"
EOF

第二个文件基本上包含相同的信息,systemd 和一些图形桌面环境会使用它。运行命令创建该文件
修改VERSION_CODENAME

1
2
3
4
5
6
7
8
cat > /etc/os-release << "EOF"
NAME="Linux From Scratch"
VERSION="12.2"
ID=lfs
PRETTY_NAME="Linux From Scratch 12.2"
VERSION_CODENAME="Finale"
HOME_URL="https://www.linuxfromscratch.org/lfs/"
EOF

现在所有工作都完成了,退出chroot环境

1
logout

解除虚拟文件系统的挂载

1
2
3
4
5
6
umount -v $LFS/dev/pts
mountpoint -q $LFS/dev/shm && umount -v $LFS/dev/shm
umount -v $LFS/dev
umount -v $LFS/run
umount -v $LFS/proc
umount -v $LFS/sys

解除 LFS 文件系统的挂载

1
umount -v $LFS

安装到虚拟硬盘上

之前已经安装好了整个LFS,但因为是在U盘上安装的,接下来会讲如何做可启动的镜像
首先确认LFS占用了多大空间,然后用dd制作一个大小差不多的文件,这里选择30G

1
dd if=/dev/zero of=/path/to/your/img bs 1M count 30000

把这个文件挂载成回环设备,然后通过losetup -l确认回环设备的名字,我的是/dev/loop0

1
2
losetup -fP /path/to/your/img
losetup -l

对这个回环设备进行分区操作

1
fdisk /dev/loop0

在这个块设备上建立一个分区,然后在这个分区上建立一个ext4文件系统,我的分区名字叫做/dev/loop0p1

1
mkfs.ext4 /dev/loop0p1`

现在挂载这个分区

1
mount /dev/loop0p1 /mnt/temp/

把LFS复制到分区里

1
cp $LFS/* /mnt/temp

把环境变量$LFS改成现在这个目录,像之前一样挂载好内核虚拟文件系统,然后进入chroot环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export LFS=/mnt/temp

mount -v --bind /dev $LFS/dev
mount -vt devpts devpts -o gid=5,mode=0620 $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run

if [ -h $LFS/dev/shm ]; then
install -v -d -m 1777 $LFS$(realpath /dev/shm)
else
mount -vt tmpfs -o nosuid,nodev tmpfs $LFS/dev/shm
fi

chroot "$LFS" /usr/bin/env -i \
HOME=/root \
TERM="$TERM" \
PS1='(lfs chroot) \u:\w\$ ' \
PATH=/usr/bin:/usr/sbin \
MAKEFLAGS="-j$(nproc)" \
TESTSUITEFLAGS="-j$(nproc)" \
/bin/bash --login

现在再安装一遍GRUB,这样就可以用虚拟硬盘上的GRUB启动系统了

1
grub-install --boot-directory /boot --target i386-pc --allow-floppy /dev/loop0 --directory /usr/lib/grub/i386-pc

因为重新制作了文件系统,所以相应的/etc/fstab/boot/grub/grub.cfg都需要像之前提到的一样修改

退出系统并卸载所有分区,现在可以用QEMU启动系统了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
exit

umount -v $LFS/dev/pts
mountpoint -q $LFS/dev/shm && umount -v $LFS/dev/shm
umount -v $LFS/dev
umount -v $LFS/run
umount -v $LFS/proc
umount -v $LFS/sys

umount -v $LFS

losetup -d /dev/loop0

qemu-system-x86_84 -hda /path/to/your/img
Author:NakanoMiku39
Link:http://nakanomiku39.github.io/2024/10/05/%E6%9E%84%E9%80%A0%E5%9F%BA%E4%BA%8Ex86-64%E7%9A%84LFS%EF%BC%884%EF%BC%89/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可