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

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、开机自启动


http://www.kler.cn/a/594069.html

相关文章:

  • 深入理解 RLP 编码与 JSON:原理、应用与比较
  • 详细介绍VUE,带你了解VUE!!!
  • 光谱仪与光谱相机的核心区别与协同应用
  • ABAP 长文本编辑器
  • 【文件分类助手V1.0b】支持自定义后缀分类整理及目录文档自动生成,方便大家美化管理自己的PC文件库支持Win10/11
  • go~协程阻塞分析
  • 事件响应计划:网络弹性的关键
  • C# 表达式目录树:深入探讨表达式树的概念与应用
  • Excel知识库与LLM结合的解决方案分析
  • Uni-App 双栏联动滚动组件开发详解 (电梯导航)
  • 使用 `pytest` 框架时,可以通过极限封装将 YAML 文件的读取、解析
  • 8、Python 字符串处理与正则表达式实战指南
  • 【css酷炫效果】纯CSS实现全屏粒子连线
  • Qt 实现波浪填充的圆形进度显示
  • 【Java】TCP网络编程:从可靠传输到Socket实战
  • coze ai assistant Task5
  • 学术PPT模板_院士_国家科学技术奖_杰青基金_长江学者特聘教授_校企联聘长江_重点研发_优青_青长_青拔ppt制作案例
  • RAG优化:python实现基于问题生成(扩展语义表示、优化检索粒度和提升上下文关联性)的文档增强RAG
  • 高级数据结构应用:并查集、跳表、布隆过滤器与缓存结构
  • Android Jetpack Compose介绍