LFS实战之三:构建文件系统

前言

linux操作系统除了需要内核以外,还需要各种基础软件辅助,才能正常运行,而基础软件是由文件系统存储并管理的,本章将展示一个最简嵌入式linux发行版需要的基础软件包的构建过程。

一、文件系统框架

拓展知识: 文件系统层级标准FHS

mkdir -pv ${CLFS}/targetfs/{bin,boot,dev,etc,home,lib/{firmware,modules}}
mkdir -pv ${CLFS}/targetfs/{mnt,opt,proc,sbin,srv,sys}
mkdir -pv ${CLFS}/targetfs/var/{cache,lib,local,lock,log,opt,run,spool}
install -dv -m 0750 ${CLFS}/targetfs/root
install -dv -m 1777 ${CLFS}/targetfs/{var/,}tmp
mkdir -pv ${CLFS}/targetfs/usr/{,local/}{bin,include,lib,sbin,share,src}

二、系统权限配置

ln -svf ../proc/mounts ${CLFS}/targetfs/etc/mtab
cat > ${CLFS}/targetfs/etc/passwd << "EOF"
root::0:0:root:/root:/bin/ash
EOF
cat > ${CLFS}/targetfs/etc/group << "EOF"
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
tape:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
usb:x:14:
cdrom:x:15:
adm:x:16:root,adm,daemon
console:x:17:
cdrw:x:18:
mail:x:30:mail
news:x:31:news
uucp:x:32:uucp
users:x:100:
nogroup:x:65533:
nobody:x:65534:
EOF
touch ${CLFS}/targetfs/var/log/lastlog
chmod -v 664 ${CLFS}/targetfs/var/log/lastlog

三、编译libgcc

cp -v ${CLFS}/cross-tools/${CLFS_TARGET}/lib/libgcc_s.so.1 ${CLFS}/targetfs/lib/
# ${CLFS_TARGET}-strip ${CLFS}/targetfs/lib/libgcc_s.so.1
mkdir -pv ${CLFS}/build/musl-libgcc
pushd ${CLFS}/build/musl-libgcc
${CLFS}/sources/musl-1.1.16/configure \
  CROSS_COMPILE=${CLFS_TARGET}- \
  --prefix=/ \
  --disable-static \
  --target=${CLFS_TARGET}
make -j `nproc`
DESTDIR=${CLFS}/targetfs make install-libs -j `nproc`
popd

四、编译busybox

tar -xf ${CLFS}/archive/busybox-1.24.2.tar.bz2 -C ${CLFS}/sources
mkdir -pv ${CLFS}/build/busybox
pushd ${CLFS}/sources/busybox-1.24.2
make ARCH="${CLFS_ARCH}" O="${CLFS}/build/busybox" defconfig
sed -i 's/\(CONFIG_\)\(.*\)\(INETD\)\(.*\)=y/# \1\2\3\4 is not set/g' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_IFPLUGD\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_FEATURE_WTMP\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_FEATURE_UTMP\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_UDPSVD\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_TCPSVD\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
make ARCH="${CLFS_ARCH}" CROSS_COMPILE="${CLFS_TARGET}-" O="${CLFS}/build/busybox" -j `nproc`
make ARCH="${CLFS_ARCH}" CROSS_COMPILE="${CLFS_TARGET}-"\
  CONFIG_PREFIX="${CLFS}/targetfs" O="${CLFS}/build/busybox" install -j `nproc`
cp -v examples/depmod.pl ${CLFS}/cross-tools/bin
chmod -v 755 ${CLFS}/cross-tools/bin/depmod.pl
popd

五、iana配置

tar -xf ${CLFS}/archive/iana-etc-2.30.tar.bz2 -C ${CLFS}/sources
pushd ${CLFS}/sources/iana-etc-2.30
patch -Np1 -i ${CLFS}/archive/iana-etc-2.30-update-2.patch
cat > iana.patch << EOF
--- old/get.gawk        2024-05-19 12:58:37.570720304 +0800
+++ new/get.gawk        2024-05-19 12:58:21.170724431 +0800
@@ -14,9 +14,10 @@
     path = "/assignments/"
     # file is set by the caller
     socket = "/inet/tcp/0/" host "/80"
+    agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"

-    print "Getting http://" host path file >"/dev/stderr"
-    printf "GET %s%s HTTP/1.0\r\nHost: %s\r\n\r\n", path, file, host |& socket
+    print "Getting https://" host path file >"/dev/stderr"
+    printf "GET %s%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n", path, file, host, agent |& socket
     printf "Request sent, waiting for data... " >"/dev/stderr"

     NR = 0
EOF
patch -Np1 -i iana.patch
popd
cp -rfv ${CLFS}/sources/iana-etc-2.30 ${CLFS}/build/iana-etc
pushd ${CLFS}/build/iana-etc
make get
make STRIP=yes
make DESTDIR=${CLFS}/targetfs install
popd

六、文件系统挂载配置

cat > ${CLFS}/targetfs/etc/fstab << "EOF"
# file-system  mount-point  type   options          dump  fsck
EOF

七、编译linux内核

mkdir -pv ${CLFS}/build/linux
pushd ${CLFS}/sources/linux-4.9.22
# 解决yylloc多重定义问题
sed -i "305a\HOSTCFLAGS += -fcommon" Makefile
make mrproper
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- O="${CLFS}/build/linux" defconfig
# 添加initramfs支持
sed -i "s/# CONFIG_BLK_DEV_RAM is not set/CONFIG_BLK_DEV_RAM=y/g" ${CLFS}/build/linux/.config
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- O="${CLFS}/build/linux" olddefconfig
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- O="${CLFS}/build/linux" Image modules -j `nproc`
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- \
    INSTALL_MOD_PATH=${CLFS}/targetfs O="${CLFS}/build/linux" modules_install -j `nproc`
install ${CLFS}/build/linux/vmlinux ${CLFS}/build
install ${CLFS}/build/linux/arch/arm64/boot/Image ${CLFS}/build
popd

八、启动脚本配置

tar -xf ${CLFS}/archive/master.tar.gz -C ${CLFS}/sources
pushd ${CLFS}/sources/bootscripts-embedded-master
make DESTDIR=${CLFS}/targetfs install-bootscripts
popd

九、设备识别规则配置

cat > ${CLFS}/targetfs/etc/mdev.conf<< "EOF"
# /etc/mdev/conf

# Devices:
# Syntax: %s %d:%d %s
# devices user:group mode

# null does already exist; therefore ownership has to be changed with command
null    root:root 0666  @chmod 666 $MDEV
zero    root:root 0666
grsec   root:root 0660
full    root:root 0666

random  root:root 0666
urandom root:root 0444
hwrandom root:root 0660

# console does already exist; therefore ownership has to be changed with command
#console        root:tty 0600   @chmod 600 $MDEV && mkdir -p vc && ln -sf ../$MDEV vc/0
console root:tty 0600 @mkdir -pm 755 fd && cd fd && for x in 0 1 2 3 ; do ln -sf /proc/self/fd/$x $x; done

fd0     root:floppy 0660
kmem    root:root 0640
mem     root:root 0640
port    root:root 0640
ptmx    root:tty 0666

# ram.*
ram([0-9]*)     root:disk 0660 >rd/%1
loop([0-9]+)    root:disk 0660 >loop/%1
sd[a-z].*       root:disk 0660 */lib/mdev/usbdisk_link
hd[a-z][0-9]*   root:disk 0660 */lib/mdev/ide_links
md[0-9]         root:disk 0660

tty             root:tty 0666
tty[0-9]        root:root 0600
tty[0-9][0-9]   root:tty 0660
ttyS[0-9]*      root:tty 0660
pty.*           root:tty 0660
vcs[0-9]*       root:tty 0660
vcsa[0-9]*      root:tty 0660

ttyLTM[0-9]     root:dialout 0660 @ln -sf $MDEV modem
ttySHSF[0-9]    root:dialout 0660 @ln -sf $MDEV modem
slamr           root:dialout 0660 @ln -sf $MDEV slamr0
slusb           root:dialout 0660 @ln -sf $MDEV slusb0
fuse            root:root  0666

# dri device
card[0-9]       root:video 0660 =dri/

# alsa sound devices and audio stuff
pcm.*           root:audio 0660 =snd/
control.*       root:audio 0660 =snd/
midi.*          root:audio 0660 =snd/
seq             root:audio 0660 =snd/
timer           root:audio 0660 =snd/

adsp            root:audio 0660 >sound/
audio           root:audio 0660 >sound/
dsp             root:audio 0660 >sound/
mixer           root:audio 0660 >sound/
sequencer.*     root:audio 0660 >sound/

# misc stuff
agpgart         root:root 0660  >misc/
psaux           root:root 0660  >misc/
rtc             root:root 0664  >misc/

# input stuff
event[0-9]+     root:root 0640 =input/
mice            root:root 0640 =input/
mouse[0-9]      root:root 0640 =input/
ts[0-9]         root:root 0600 =input/

# v4l stuff
vbi[0-9]        root:video 0660 >v4l/
video[0-9]      root:video 0660 >v4l/

# dvb stuff
dvb.*           root:video 0660 */lib/mdev/dvbdev

# load drivers for usb devices
usbdev[0-9].[0-9]       root:root 0660 */lib/mdev/usbdev
usbdev[0-9].[0-9]_.*    root:root 0660

# net devices
tun[0-9]*       root:root 0600 =net/
tap[0-9]*       root:root 0600 =net/

# zaptel devices
zap(.*)         root:dialout 0660 =zap/%1
dahdi!(.*)      root:dialout 0660 =dahdi/%1

# raid controllers
cciss!(.*)      root:disk 0660 =cciss/%1
ida!(.*)        root:disk 0660 =ida/%1
rd!(.*)         root:disk 0660 =rd/%1

sr[0-9]         root:cdrom 0660 @ln -sf $MDEV cdrom 

# hpilo
hpilo!(.*)      root:root 0660 =hpilo/%1

# xen stuff
xvd[a-z]        root:root 0660 */lib/mdev/xvd_links
EOF

十、bash环境配置

cat > ${CLFS}/targetfs/etc/profile << "EOF"
# /etc/profile

# Set the initial path
export PATH=/bin:/usr/bin

if [ `id -u` -eq 0 ] ; then
        PATH=/bin:/sbin:/usr/bin:/usr/sbin
        unset HISTFILE
fi

# Setup some environment variables.
export USER=`id -un`
export LOGNAME=$USER
export HOSTNAME=`/bin/hostname`
export HISTSIZE=1000
export HISTFILESIZE=1000
export PAGER='/bin/more '
export EDITOR='/bin/vi'

# End /etc/profile
EOF

十一、init脚本配置

cat > ${CLFS}/targetfs/etc/inittab<< "EOF"
# /etc/inittab

::sysinit:/etc/rc.d/startup

tty1::respawn:/sbin/getty 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
tty3::respawn:/sbin/getty 38400 tty3
tty4::respawn:/sbin/getty 38400 tty4
tty5::respawn:/sbin/getty 38400 tty5
tty6::respawn:/sbin/getty 38400 tty6

# Put a getty on the serial line (for a terminal).  Uncomment this line if
# you're using a serial console on ttyAMA0, or uncomment and adjust it if using a
# serial console on a different serial port such as ttyS0.
::respawn:/sbin/getty -L ttyAMA0 115200 vt100

::shutdown:/etc/rc.d/shutdown
::ctrlaltdel:/sbin/reboot
EOF

十二、主机名配置

echo "[clfs]" > ${CLFS}/targetfs/etc/HOSTNAME

十三、hosts配置

cat > ${CLFS}/targetfs/etc/hosts << "EOF"
# Begin /etc/hosts (network card version)

127.0.0.1 localhost
# [192.168.1.1] [<HOSTNAME>.example.org] [HOSTNAME]

# End /etc/hosts (network card version)
EOF

十四、网络配置

mkdir -pv ${CLFS}/targetfs/etc/network/if-{post-{up,down},pre-{up,down},up,down}.d
mkdir -pv ${CLFS}/targetfs/usr/share/udhcpc

cat > ${CLFS}/targetfs/etc/network/interfaces << "EOF"
auto eth0
iface eth0 inet dhcp
EOF

cat > ${CLFS}/targetfs/usr/share/udhcpc/default.script << "EOF"
#!/bin/sh
# udhcpc Interface Configuration
# Based on http://lists.debian.org/debian-boot/2002/11/msg00500.html
# udhcpc script edited by Tim Riker <Tim@Rikers.org>

[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1

RESOLV_CONF="/etc/resolv.conf"
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"

case "$1" in
        deconfig)
                /sbin/ifconfig $interface 0.0.0.0
                ;;

        renew|bound)
                /sbin/ifconfig $interface $ip $BROADCAST $NETMASK

                if [ -n "$router" ] ; then
                        while route del default gw 0.0.0.0 dev $interface ; do
                                true
                        done

                        for i in $router ; do
                                route add default gw $i dev $interface
                        done
                fi

                echo -n > $RESOLV_CONF
                [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
                for i in $dns ; do
                        echo nameserver $i >> $RESOLV_CONF
                done
                ;;
esac

exit 0
EOF

chmod +x ${CLFS}/targetfs/usr/share/udhcpc/default.script

十五、编译zlib

tar -xf ${CLFS}/archive/zlib-1.2.8.tar.gz -C ${CLFS}/sources
cp -rvf ${CLFS}/sources/zlib-1.2.8 ${CLFS}/build/zlib
pushd ${CLFS}/build/zlib
CFLAGS="-Os" ./configure --shared
make -j `nproc`
make prefix=${CLFS}/cross-tools/${CLFS_TARGET} install -j `nproc`
cp -v ${CLFS}/cross-tools/${CLFS_TARGET}/lib/libz.so.1.2.8 ${CLFS}/targetfs/lib/
ln -sv libz.so.1.2.8 ${CLFS}/targetfs/lib/libz.so.1
popd

十六、编译netplug

tar -xf ${CLFS}/archive/netplug-1.2.9.2.tar.bz2 -C ${CLFS}/sources
pushd ${CLFS}/sources/netplug-1.2.9.2
patch -Np1 -i ${CLFS}/archive/netplug-1.2.9.2-fixes-1.patch
cat > not_support_hg.patch << EOF
--- old/Makefile        2024-05-19 14:11:38.039630691 +0800
+++ new/Makefile        2024-05-19 14:16:44.249553189 +0800
@@ -30,19 +30,5 @@
        install $(install_opts) -m 755 scripts/rc.netplugd $(DESTDIR)/$(initdir)/netplugd
        install $(install_opts) -m 444 man/man8/netplugd.8 $(DESTDIR)/$(mandir)/man8

-hg_root := $(shell hg root)
-tar_root := netplug-$(version)
-tar_file := $(hg_root)/$(tar_root).tar.bz2
-files := $(shell hg manifest)
-
-tarball: $(tar_file)
-
-$(tar_file): $(files)
-       mkdir -p $(hg_root)/$(tar_root)
-       echo $(files) | tr ' ' '\n' | \
-         xargs -i cp -a --parents {} $(hg_root)/$(tar_root)
-       tar -C $(hg_root) -c -f - $(tar_root) | bzip2 -9 > $(tar_file)
-       rm -rf $(hg_root)/$(tar_root)
-
 clean:
        -rm -f netplugd *.o *.tar.bz2
EOF
patch -Np1 -i not_support_hg.patch
popd
cp -rvf ${CLFS}/sources/netplug-1.2.9.2 ${CLFS}/build/netplug
pushd ${CLFS}/build/netplug
make -j `nproc`
make DESTDIR=${CLFS}/targetfs install -j `nproc`
popd
pushd ${CLFS}/sources/bootscripts-embedded-master
make install-netplug DESTDIR=${CLFS}/targetfs
popd

十七、编译dropbear

tar -xf ${CLFS}/archive/dropbear-2013.60.tar.bz2 -C ${CLFS}/sources
pushd ${CLFS}/sources/dropbear-2013.60
sed -i 's/.*mandir.*//g' Makefile.in
popd
mkdir -pv ${CLFS}/build/dropbear
pushd ${CLFS}/build/dropbear
CC="${CC} -Os" ${CLFS}/sources/dropbear-2013.60/configure --prefix=/usr --host=${CLFS_TARGET}
make MULTI=1 \
  PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" -j `nproc`
make MULTI=1 \
  PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" \
  install DESTDIR=${CLFS}/targetfs -j `nproc`
install -dv ${CLFS}/targetfs/etc/dropbear
popd
pushd ${CLFS}/sources/bootscripts-embedded-master
make install-dropbear DESTDIR=${CLFS}/targetfs
popd

十八、编译wireless tools

tar -xf ${CLFS}/archive/wireless_tools.29.tar.gz -C ${CLFS}/sources
pushd ${CLFS}/sources/wireless_tools.29
sed -i s/gcc/\$\{CLFS\_TARGET\}\-gcc/g Makefile
sed -i s/\ ar/\ \$\{CLFS\_TARGET\}\-ar/g Makefile
sed -i s/ranlib/\$\{CLFS\_TARGET\}\-ranlib/g Makefile
popd
cp -rvf ${CLFS}/sources/wireless_tools.29 ${CLFS}/build/wireless_tools
pushd ${CLFS}/build/wireless_tools
make PREFIX=${CLFS}/targetfs/usr -j `nproc`
make install PREFIX=${CLFS}/targetfs/usr -j `nproc`
echo "include /usr/lib/" >> ${CLFS}/targetfs/etc/ld.so.conf
popd

十九、修改目标文件系统权限并打包

以root权限执行以下命令
扩展知识: ramfs、rootfs、initramfs的差别

export CLFS=/opt/clfs
chown -Rv root:root ${CLFS}/targetfs
chgrp -v 13 ${CLFS}/targetfs/var/log/lastlog
pushd ${CLFS}/targetfs
# 让initrd识别为initramfs
cp -rf linuxrc init
tar jcfv ${CLFS}/build/clfs-embedded.tar.bz2 *
find . | cpio -H newc -o | gzip -9 > ${CLFS}/build/initramfs.cpio.gz
popd

总结

本章对linux内核和基础系统工具进行编译集成,最终生成了一个用于操作系统启动的文件系统。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值