当前位置: 首页 > news >正文

63. 根文件系统构建

一、根文件系统简介

根文件系统也叫做rootfs。大家学习STM32的W25Q256、SD卡的时候接触过FATFS文件系统。Rootfs?=FATFS。不等于!
FATFS这类的文件系统属于Linux内核的一部分,属于软件代码。
那么ROOTFS是什么,根文件系统=“根”、“文件”、“系统”。根文件系统就是一堆的文件、比如软件、配置文件等,这些文件是Linux运行所必须的,将他们组合在一起就构成了跟文件系统。
根文件系统就是一个“文件夹”,此“文件夹”有很多个文件,这些文件是linux运行所必须的,但是无法放到内核里面去的。比如命令、库、配置文件等等。所有这些软件需要我们自己构建。
/就是Linux根文件系统。

二、BusyBox构建根文件系统

https://busybox.net/
在这里插入图片描述

Download Source

在这里插入图片描述

构建根文件系统,busybox。还有很多成熟化的根文件系统构建方式,buildroot,yocto。构建的根文件系统调试我们通过nfs网络挂载,也就是跟文件系统存放到ubuntu下,开发板启动以后通过nfs服务使用ubuntu下的跟文件系统。

1、修改makefile,添加交叉编译器

修改ARCH和CROSS_COMPILE。
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- 

在这里插入图片描述
在这里插入图片描述

2、busybox支持中文字符

如果默认直接编译 busybox 的话,在使用 SecureCRT 的时候中文字符是显示不正常的,中文字符会显示为“?”,比如你的中文目录,中文文件都显示为“?”。不知道从哪个版本开始 busybox中的 shell 命令对中文输入即显示做了限制,即使内核支持中文但在 shell 下也依然无法正确显示。

所以我们需要修改 busybox 源码,取消 busybox 对中文显示的限制,打开文件 busybox- 1.29.0/libbb/printable_string.c,找到函数 printable_string,缩减后的函数内容如下

/* vi: set sw=4 ts=4: */
/*
 * Unicode support routines.
 *
 * Copyright (C) 2010 Denys Vlasenko
 *
 * Licensed under GPLv2, see file LICENSE in this source tree.
 */
#include "libbb.h"
#include "unicode.h"

const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
{
    char *dst;
    const char *s;

    s = str;
    while (1) {
        unsigned char c = *s;
        if (c == '\0') {
            /* 99+% of inputs do not need conversion */
            if (stats) {
                stats->byte_count = (s - str);
                stats->unicode_count = (s - str);
                stats->unicode_width = (s - str);
            }
            return str;
        }
        if (c < ' ')
            break;
        if (c >= 0x7f)
            break;
        s++;
    }

#if ENABLE_UNICODE_SUPPORT
    dst = unicode_conv_to_printable(stats, str);
#else
    {
        char *d = dst = xstrdup(str);
        while (1) {
            unsigned char c = *d;
            if (c == '\0')
                break;
            if (c < ' ' || c >= 0x7f)
                *d = '?';
            d++;
        }
        if (stats) {
            stats->byte_count = (d - dst);
            stats->unicode_count = (d - dst);
            stats->unicode_width = (d - dst);
        }
    }
#endif
    return auto_string(dst);
}

改为

const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
{
    char *dst;
    const char *s;

    s = str;
    while (1) {
        unsigned char c = *s;
        if (c == '\0') {
            /* 99+% of inputs do not need conversion */
            if (stats) {
                stats->byte_count = (s - str);
                stats->unicode_count = (s - str);
                stats->unicode_width = (s - str);
            }
            return str;
        }
        if (c < ' ')
            break;
        // if (c >= 0x7f)
        //  break;
        s++;
    }

#if ENABLE_UNICODE_SUPPORT
    dst = unicode_conv_to_printable(stats, str);
#else
    {
        char *d = dst = xstrdup(str);
        while (1) {
            unsigned char c = *d;
            if (c == '\0')
                break;
            // if (c < ' ' || c >= 0x7f)
            if (c < ' ')
                *d = '?';
            d++;
        }
        if (stats) {
            stats->byte_count = (d - dst);
            stats->unicode_count = (d - dst);
            stats->unicode_width = (d - dst);
        }
    }
#endif
    return auto_string(dst);
}

接着打开文件 busybox-1.29.0/libbb/unicode.c,找到如下内容:

static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
{
    char *dst;
    unsigned dst_len;
    unsigned uni_count;
    unsigned uni_width;

    if (unicode_status != UNICODE_ON) {
        char *d;
        if (flags & UNI_FLAG_PAD) {
            d = dst = xmalloc(width + 1);
            while ((int)--width >= 0) {
                unsigned char c = *src;
                if (c == '\0') {
                    do
                        *d++ = ' ';
                    while ((int)--width >= 0);
                    break;
                }
                *d++ = (c >= ' ' && c < 0x7f) ? c : '?';
                src++;
            }
            *d = '\0';
        } else {
            d = dst = xstrndup(src, width);
            while (*d) {
                unsigned char c = *d;
                if (c < ' ' || c >= 0x7f)
                    *d = '?';
                d++;
            }
        }
        if (stats) {
            stats->byte_count = (d - dst);
            stats->unicode_count = (d - dst);
            stats->unicode_width = (d - dst);
        }
        return dst;
    }

    dst = NULL;
    uni_count = uni_width = 0;
    dst_len = 0;
    while (1) {
        int w;
        wchar_t wc;

#if ENABLE_UNICODE_USING_LOCALE
        {
            mbstate_t mbst = { 0 };
            ssize_t rc = mbsrtowcs(&wc, &src, 1, &mbst);
            /* If invalid sequence is seen: -1 is returned,
             * src points to the invalid sequence, errno = EILSEQ.
             * Else number of wchars (excluding terminating L'\0')
             * written to dest is returned.
             * If len (here: 1) non-L'\0' wchars stored at dest,
             * src points to the next char to be converted.
             * If string is completely converted: src = NULL.
             */
            if (rc == 0) /* end-of-string */
                break;
            if (rc < 0) { /* error */
                src++;
                goto subst;
            }
            if (!iswprint(wc))
                goto subst;
        }
#else
        src = mbstowc_internal(&wc, src);
        /* src is advanced to next mb char
         * wc == ERROR_WCHAR: invalid sequence is seen
         * else: wc is set
         */
        if (wc == ERROR_WCHAR) /* error */
            goto subst;
        if (wc == 0) /* end-of-string */
            break;
#endif
        if (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR)
            goto subst;
        w = wcwidth(wc);
        if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) /* non-printable wchar */
         || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
         || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
        ) {
 subst:
            wc = CONFIG_SUBST_WCHAR;
            w = 1;
        }
        width -= w;
        /* Note: if width == 0, we still may add more chars,
         * they may be zero-width or combining ones */
        if ((int)width < 0) {
            /* can't add this wc, string would become longer than width */
            width += w;
            break;
        }

        uni_count++;
        uni_width += w;
        dst = xrealloc(dst, dst_len + MB_CUR_MAX);
#if ENABLE_UNICODE_USING_LOCALE
        {
            mbstate_t mbst = { 0 };
            dst_len += wcrtomb(&dst[dst_len], wc, &mbst);
        }
#else
        dst_len += wcrtomb_internal(&dst[dst_len], wc);
#endif
    }

    /* Pad to remaining width */
    if (flags & UNI_FLAG_PAD) {
        dst = xrealloc(dst, dst_len + width + 1);
        uni_count += width;
        uni_width += width;
        while ((int)--width >= 0) {
            dst[dst_len++] = ' ';
        }
    }
    dst[dst_len] = '\0';
    if (stats) {
        stats->byte_count = dst_len;
        stats->unicode_count = uni_count;
        stats->unicode_width = uni_width;
    }

    return dst;
}

改为

static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
{
    char *dst;
    unsigned dst_len;
    unsigned uni_count;
    unsigned uni_width;

    if (unicode_status != UNICODE_ON) {
        char *d;
        if (flags & UNI_FLAG_PAD) {
            d = dst = xmalloc(width + 1);
            while ((int)--width >= 0) {
                unsigned char c = *src;
                if (c == '\0') {
                    do
                        *d++ = ' ';
                    while ((int)--width >= 0);
                    break;
                }
                /* *d++ = (c >= ' ' && c < 0x7f) ? c : '?'; */
                *d++ = (c >= ' ') ? c : '?';
                src++;
            }
            *d = '\0';
        } else {
            d = dst = xstrndup(src, width);
            while (*d) {
                unsigned char c = *d;
                /* if (c < ' ' || c >= 0x7f) */
                if(c < ' ')
                    *d = '?';
                d++;
            }
        }
        if (stats) {
            stats->byte_count = (d - dst);
            stats->unicode_count = (d - dst);
            stats->unicode_width = (d - dst);
        }
        return dst;
    }

    dst = NULL;
    uni_count = uni_width = 0;
    dst_len = 0;
    while (1) {
        int w;
        wchar_t wc;

#if ENABLE_UNICODE_USING_LOCALE
        {
            mbstate_t mbst = { 0 };
            ssize_t rc = mbsrtowcs(&wc, &src, 1, &mbst);
            /* If invalid sequence is seen: -1 is returned,
             * src points to the invalid sequence, errno = EILSEQ.
             * Else number of wchars (excluding terminating L'\0')
             * written to dest is returned.
             * If len (here: 1) non-L'\0' wchars stored at dest,
             * src points to the next char to be converted.
             * If string is completely converted: src = NULL.
             */
            if (rc == 0) /* end-of-string */
                break;
            if (rc < 0) { /* error */
                src++;
                goto subst;
            }
            if (!iswprint(wc))
                goto subst;
        }
#else
        src = mbstowc_internal(&wc, src);
        /* src is advanced to next mb char
         * wc == ERROR_WCHAR: invalid sequence is seen
         * else: wc is set
         */
        if (wc == ERROR_WCHAR) /* error */
            goto subst;
        if (wc == 0) /* end-of-string */
            break;
#endif
        if (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR)
            goto subst;
        w = wcwidth(wc);
        if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) /* non-printable wchar */
         || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
         || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
        ) {
 subst:
            wc = CONFIG_SUBST_WCHAR;
            w = 1;
        }
        width -= w;
        /* Note: if width == 0, we still may add more chars,
         * they may be zero-width or combining ones */
        if ((int)width < 0) {
            /* can't add this wc, string would become longer than width */
            width += w;
            break;
        }

        uni_count++;
        uni_width += w;
        dst = xrealloc(dst, dst_len + MB_CUR_MAX);
#if ENABLE_UNICODE_USING_LOCALE
        {
            mbstate_t mbst = { 0 };
            dst_len += wcrtomb(&dst[dst_len], wc, &mbst);
        }
#else
        dst_len += wcrtomb_internal(&dst[dst_len], wc);
#endif
    }

    /* Pad to remaining width */
    if (flags & UNI_FLAG_PAD) {
        dst = xrealloc(dst, dst_len + width + 1);
        uni_count += width;
        uni_width += width;
        while ((int)--width >= 0) {
            dst[dst_len++] = ' ';
        }
    }
    dst[dst_len] = '\0';
    if (stats) {
        stats->byte_count = dst_len;
        stats->unicode_count = uni_count;
        stats->unicode_width = uni_width;
    }

    return dst;
}

3、配置busybox

我们一般使用默认配置即可,因此使用如下命令先使用默认配置来配置一下 busybox: 
make defconfig
ls -a

有.config 说明配置成功

busybox 也支持图形化配置,通过图形化配置我们可以进一步选择自己想要的功能,输入如下命令打开图形化配置界面: 打开图形化配置界面

make menuconfig

make menuconfig报错
busybox/busybox-1.29.0# make menuconfig
HOSTCC scripts/kconfig/lxdialog/checklist.o
: fatal error: curses.h: No such file or directory
安装:

sudo apt-get install libncurses5-dev libncursesw5-dev

配置路径如下:
Location:
-> Settings
-> Build static binary (no shared libs

选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大。动态编译的话要求根文件系统中有库文件,但是编译出来的 busybox 会小很多。这里我们不能采用静态编译!因为采用静态编译的话 DNS 会出问题!无法进行域名解析,配置如图 38.2.2.

在这里插入图片描述

继续配置如下路径配置项:
Location: -> Settings
-> vi-style line editing commands

在这里插入图片描述

继续配置如下路径配置项: Location:
-> Linux Module Utilities -> Simplified modutils
默认会选中“Simplified modutils”,这里我们要取消勾选!!结果如图 38.2.2.5 所示
在这里插入图片描述

继续配置如下路径配置项: Location:
-> Linux System Utilities
-> mdev (16 kb) //确保下面的全部选中,默认都是选中的
在这里插入图片描述

最后就是使能 busybox 的 unicode 编码以支持中文,配置路径如下: Location:
-> Settings
-> Support Unicode -> Check $LC_ALL, $LC_CTYPE and $LANG environment variables //选中//选中
在这里插入图片描述
在这里插入图片描述

4、编译busybox

配置好 busybox 以后就可以编译了,我们可以指定编译结果的存放目录,我们肯定要将编译结果存放到前面创建的 rootfs 目录中,输入如下命令:

make -j12 install CONFIG_PREFIX=/home/mk/nfs/rootfs 

编译完成以后会在 busybox 的所有工具和文件就会被安装到 rootfs 目录中, rootfs 目录内容如图 38.2.2.9 所示:
在这里插入图片描述

从图 38.2.2.9 可以看出, rootfs 目录下有 bin、 sbin 和 usr 这三个目录,以及 linuxrc 这个文件。前面说过 Linux 内核 init 进程最后会查找用户空间的 init 程序,找到以后就会运行这个用户空间的 init 程序,从而切换到用户态。如果 bootargs 设置 init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。
busybox 的工作就完成了,但是此时的根文件系统还不能使用,还需要一些其他的文件,我们继续来完善 rootfs。

5、拷贝库文件。

库文件就是交叉编译器的库文件。

1. 先是rootfs/lib目录

在 rootfs 中创建一个名为“lib”的文件夹 ,进入如下路径对应的目录:

/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linuxgnueabihf/libc/lib

此目录下有很多的so(是通配符)和.a 文件,这些就是库文件,将此目录下所有的so*和.a文件都拷贝到 rootfs/lib 目录中, 拷贝命令如下:
cp so *.a /home/mike/nfs/rootfs/lib/ -d
后面的“-d”表示拷贝符号链接,这里有个比较特殊的库文件: ld-linux-armhf.so.3,此库文件也是个符号链接,相当于 Windows 下的快捷方式。会链接到库 ld-2.19-2014.08-1-git.so 上,输
入命令“ls ld-linux-armhf.so.3 -l”查看此文件详细信息,如图 38.2.3.1 所示
ld-linux-armhf.so.3 后面有个“->”,表示其是个软连接文件,链接到文件 ld-2.19-2014.08-1-git.so,因为其是一个“快捷方式”,因此大小只有 24B。但是, ld-linuxarmhf.so.3 不能作为符号链接,否则的话在根文件系统中执行程序无法执行!所以我们需要 ldlinux-armhf.so.3 完成逆袭,由“快捷方式”变为“本尊”,方法很简单,那就是重新复制 ld-linuxarmhf.so.3,只是不复制软链接即可,先将 rootfs/lib 中的 ld-linux-armhf.so.3 文件删除掉,命令如下:

rm ld-linux-armhf.so.3 

然 后 重 新 进 入 到 /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/armlinux-gnueabihf/libc/lib 目录中,重新拷贝 ld-linux-armhf.so.3,命令如下:

cp ld-linux-armhf.so.3 /home/mike/nfs/rootfs/lib/ 

拷贝完成以后再到 rootfs/lib 目录下查看 ld-linux-armhf.so.3 文件详细信息,如图 38.2.3.2 所示
-rwxr-xr-x 1 xxx xxx 724392 Feb 13 21:28 ld-linux-armhf.so.3
此时 ld-linux-armhf.so.3 已经不是软连接了,而是实实在在的一个库文件,而且文件大小为 724392B。
继续进入如下目录中:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
此目录下也有很多的的so和.a 库文件,我们将其也拷贝到 rootfs/lib 目录中,命令如下:

cp *so* *.a /home/mike/nfs/rootfs/lib/ -d

rootfs/lib 目录的库文件就这些了,完成以后的 rootfs/lib 目录如图 38.2.3.3 所示
在这里插入图片描述

2. 然后是rootfs/usr/lib目录

在 rootfs 的 usr 目录下创建一个名为 lib 的目录,将如下目录中的库文件拷贝到 rootfs/usr/lib目录下:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
将此目录下的 so 和.a 库文件都拷贝到 rootfs/usr/lib 目录中,命令如下:

cp *so* *.a /home/mike/nfs/rootfs/usr/lib/ -d

完成以后的 rootfs/usr/lib 目录如图 38.2.3.4 所示
在这里插入图片描述

至此,根文件系统的库文件就全部添加好了,可以使用“du”命令来查看一下 rootfs/lib 和rootfs/usr/lib 这两个目录的大小,命令如下:
cd rootfs
//进入根文件系统目录

du ./lib ./usr/lib/ -sh 
//查看 lib 和 usr/lib 这两个目录的大小

结果如图 38.2.3.5 所示:
在这里插入图片描述

6、创建其他文件夹

 mkdir dev proc mnt sys tmp root

目前来看,这个根文件系统好像已经准备好了,究竟有没有准备好,直接测一下就知道了!

三、根文件系统初步测试

为了方便测试,我们采用挂在网络根文件系统,nfs。要求:
1、linux内核网络驱动要工作正常。
2、设置uboot的bootargs,也就是linux内核的命令行参数。
在这里插入图片描述

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/cfb345b44ff9493dba25add44080f03b.png)

从ubuntu的tftpboot里面加载我们前面移植的uboot、zImage和dtb,设置bootcmd。

bootcmd=tftp 80800000 zImage;tftp 83000000 imx6ull-my-emmc.dtb;bootz 80800000 - 83000000;

修改

bootargs
bootargs=console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw;

setenv bootargs 'console=ttymxc0,115200 rw root=/dev/nfs nfsroot=192.168.31.213:/home/mk/nfs/rootfs ip=192.168.31.50:192.168.31.213:192.168.31.1:255.255.255.0::eth0:off'
setenv serverip 192.168.31.213
saveenv

测试的时候发现:
在这里插入图片描述

也就是提示 文件系统为只读,这是因为booargs参数没设置全。

还有问题

can't run '/etc/init.d/rcS': No such file or directory

四、完善根文件系统

五、根文件系统其他功能测试

1、测试应用程序的运行
编写helloc.c,测试软件试运行在ARM开发板上,因此编译的时候要使用交叉编译器。编译完成以后使用file命令查看可执行文件信息。
应用程序后台运行 xxx &。关闭某个软件后台运行,输入ps命令查看当前所有软件的PID。查到hello的PID是77。通过kill -9 77(PID).

2、中文字符测试

3、开机自启动

相关文章:

  • STM32 模拟SPI 模式0
  • 大模型+知识图谱:赋能知识智能新升级
  • Harmony OS【获取本地json数据的方法】
  • 【el-upload】el-upload组件 - list-type=“picture“ 时,文件预览展示优化
  • dfs(二十)257. 二叉树的所有路径
  • /proc/[pid]/maps介绍和pmap介绍、RSS
  • 《深入理解 TypeScript:函数类型与泛型全解析》(万字长文)
  • 【MyDB】5-索引管理之 1-索引管理思路概览
  • Centos7配置本地yum源
  • 大白话读懂java对象创建的过程
  • 织梦DedeCMS数据库表说明大全
  • django入门教程之request和reponse【二】
  • Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(六)
  • 联想拯救者触摸板会每次开机都自动关闭、联想笔记本触摸板关闭、笔记本电脑触摸板自动关闭的解决方法
  • 演员马晓琳正式加入创星演员出道计划,开启演艺事业新篇章
  • 基于YOLOv8与ByteTrack的车辆行人多目标检测与追踪系统
  • @maptalks/gl-layers中的VectorTileLayer的setStyle属性的全部line配置
  • 群体智能优化算法-模拟退火优化算法(Simulated Annealing, SA,含Matlab源代码)
  • 前端Tailwind CSS面试题及参考答案
  • 实时时钟芯片HYM1381的使用(51单片机)
  • 用贝多芬八首钢琴三重奏纪念风雨并肩20年
  • 女孩患异食癖爱吃头发,一年后腹痛入院体内惊现“头发巨石”
  • 京东回应外卖系统崩溃:订单暴涨所致,已恢复
  • 2025财政观察|长三角“三公”经费普降,钱要用在刀刃上
  • 2025年中国网络文明大会将于6月10日在安徽合肥举办
  • 中国海警舰艇编队5月14日在我钓鱼岛领海巡航