嵌入式系统中的镜像升级

本文介绍了一种在嵌入式系统中实现软件升级的方法,通过创建临时内存系统来进行主系统的更新,避免了备用系统的浪费。文章详细记录了升级脚本的编写过程,包括如何利用pivot_root切换根文件系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

  刚进公司的时候,所接触到的产品使用的是ramdisk文件系统,我们使用了mkimage工具将zImage和ramdisk文件系统组合成一个包,然后再写到nandflash。这时候的系统升级只需要在uboot下将nandflash擦除,然后将新的包写到nandflash就可以了。后来使用了mmc作为储存介质后我们改用了ext4作为根文件系统,这时候就不能在uboot下直接升级了,刚开始我们做了两个系统,一个主系统和一个备用系统,升级主系统需要进入到备用系统。这样子就浪费了一个分区来做备用系统,后来发现可以在主系统下创建一个内存系统,然后切到内存系统运行来升级主系统,因此记录如下。

预备知识

 ldd命令的作用及原理

  作用:
  用来查看程序运行所需的共享库,常用来解决程序因缺少某个库文件而不能运行的一些问题。
  
  原理:
  1、首先ldd不是一个可执行程序,而只是一个shell脚本
  2、ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量,如下:
  LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、LD_VERBOSE等。当
LD_TRACE_LOADED_OBJECTS环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的dependency,而程序并不真正执行。要不你可以在shell终端测试一下,如下:
  (1) export LD_TRACE_LOADED_OBJECTS=1
  (2) 再执行任何的程序,如ls等,看看程序的运行结果
  

 pivot_root和chroot的区别

  pivot_root和chroot的主要区别是,pivot_root主要是把整个系统切换到一个新的root目录,而移除对之前root文件系统的依赖,这样你就能够umount原先的root文件系统。而chroot是针对某个进程,而系统的其它部分依旧运行于老的root目录。

升级脚本

  现将升级的步骤记录成shell脚本记录,以便日后使用。执行完这个脚本后已经运行在新的内存系统了,并且将原来的主系统挂载到了/mnt目录下,这时候只要将升级包解压到/mnt目录,然后重启。这样便完成了主系统的升级。

#!/bin/sh

RAM_ROOT=/tmp/root

[ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; }
libs() { ldd $* 2>/dev/null | sed -r 's/(.* => )?(.*) .*/\2/'; }

supivot() { # <new_root> <old_root>
    /bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
    mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
    /bin/mount -o noatime,move /proc $1/proc && \
    pivot_root $1 $1$2 || {
        /bin/umount -l $1 $1
        return 1
    }

    /bin/mount -o noatime,move $2/sys /sys
    /bin/mount -o noatime,move $2/dev /dev
    /bin/mount -o noatime,move $2/tmp /tmp
    /bin/mount -o noatime,move $2/overlay /overlay 2>&-
    return 0
}

install_file() { # <file> [ <file> ... ]
    for file in "$@"; do
        dest="$RAM_ROOT/$file"
        [ -f $file -a ! -f $dest ] && {
            dir="$(dirname $dest)"
            mkdir -p "$dir"
            cp $file $dest
        }
    done
}

install_bin() { # <file> [ <symlink> ... ]
    src=$1
    files=$1
    [ -x "$src" ] && files="$src $(libs $src)"
    install_file $files
    shift
    for link in "$@"; do {
        dest="$RAM_ROOT/$link"
        dir="$(dirname $dest)"
        mkdir -p "$dir"
        [ -f "$dest" ] || ln -s $src $dest
    }; done
}

run_ramfs() { # <command> [...]
    install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount    \
        /sbin/pivot_root /sbin/reboot /bin/sync /bin/dd /bin/grep       \
        /bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd   \
        /bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump      \
        /bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
        /bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir    \
        /bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
        /bin/mknod

    install_bin /bin/uclient-fetch /bin/wget
    install_bin /sbin/mtd
    install_bin /sbin/mount_root
    install_bin /sbin/snapshot
    install_bin /sbin/snapshot_tool
    install_bin /usr/sbin/ubiupdatevol
    install_bin /usr/sbin/ubiattach
    install_bin /usr/sbin/ubiblock
    install_bin /usr/sbin/ubiformat
    install_bin /usr/sbin/ubidetach
    install_bin /usr/sbin/ubirsvol
    install_bin /usr/sbin/ubirmvol
    install_bin /usr/sbin/ubimkvol
    install_bin /usr/sbin/partx
    install_bin /usr/sbin/losetup
    install_bin /usr/sbin/mkfs.ext4
    for file in $RAMFS_COPY_BIN; do
        install_bin ${file//:/ }
    done
    install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA

    [ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64

    supivot $RAM_ROOT /mnt || {
        echo "Failed to switch over to ramfs. Please reboot."
        exit 1
    }

#   /bin/mount -o remount,ro /mnt
#   /bin/umount -l /mnt

    grep /overlay /proc/mounts > /dev/null && {
        /bin/mount -o noatime,remount,ro /overlay
        /bin/umount -l /overlay
    }

    # spawn a new shell from ramdisk to reduce the probability of cache issues
#   exec /bin/busybox ash -c "$*"
}
run_ramfs
<think>好的,用户想了解嵌入式系统中文件镜像的概念和用途。首先,我需要回忆相关知识,并结合提供的引用内容来组织回答。 根据引用[1],嵌入式Linux系统涉及构建操作系统的基础概念,可能包括文件系统。文件镜像应该属于系统构建的一部分。引用[3]提到根文件系统制作,创建必要目录,这可能与文件镜像相关,比如如何打包这些目录成镜像。引用[2]讨论二进制文件结构,比如ELF格式,文件镜像可能也涉及二进制结构,但需要区分开。引用[4]关于库文件,可能属于镜像中的一部分内容。 首先,文件镜像嵌入式系统中通常指将整个文件系统打包成一个单一文件,方便烧录到存储设备。用途包括系统启动、分区管理、固件升级等。需要解释概念,如存储结构、格式(如JFFS2、SquashFS),然后用途方面要结合嵌入式特点,比如资源受限、只读需求等。 要注意用户可能的需求,比如他们可能在做系统开发,需要了解如何创建或使用镜像。需要确保回答结构清晰,分点说明概念和用途,并引用相关参考资料。同时生成的问题要围绕镜像的制作、格式选择、优化等,帮助用户深入理解。</think>### 嵌入式系统中文件镜像的概念与用途 #### 1. 文件镜像的概念 文件镜像(File System Image)是嵌入式系统中将整个文件系统的目录结构、配置文件、二进制程序等资源打包形成的单一文件。其核心特点包括: - **存储结构映射**:镜像文件通过特定格式(如$ext4$、$JFFS2$、$SquashFS$)完整映射存储设备的逻辑分区结构,可直接烧录到嵌入式设备的存储介质(如Flash、eMMC)中[^3]。 - **静态封装性**:在构建阶段,文件镜像会将根文件系统(rootfs)的必要目录(如`/bin`、`/lib`、`/etc`)和依赖库(如动态链接库`libc.so`)固化,确保系统启动时能正确加载[^4]。 例如,生成一个简单的SquashFS镜像的命令如下: ```bash mksquashfs rootfs/ rootfs.squashfs -comp xz ``` #### 2. 文件镜像的用途 | 用途 | 说明 | 典型场景 | |---------------------|-----------------------------------------------------------------------------------------|--------------------------| | **系统启动** | 嵌入式设备启动时,Bootloader将镜像加载到内存,内核挂载其为根文件系统(`/`)[^1]。 | 设备冷启动 | | **分区管理** | 镜像对应存储介质的独立分区(如`/boot`、`/rootfs`),支持只读或可写属性配置。 | 防止关键文件被篡改 | | **固件升级** | 通过OTA(空中下载技术)更新镜像文件,实现系统版本迭代。 | 智能家居设备远程升级 | | **资源优化** | 压缩格式镜像(如SquashFS)可减少存储占用,提升加载效率。 | 存储空间受限的传感器节点 | #### 3. 文件镜像的格式选择 - **JFFS2**:适用于NOR Flash,支持磨损均衡(Wear Leveling)[^2]。 - **UBIFS**:针对NAND Flash优化,提供更好的坏块管理。 - **SquashFS**:只读压缩格式,适合存储固件和静态资源。 例如,在嵌入式Linux中,根文件系统的典型目录结构可能包含: ``` /bin # 基础命令(如ls、cp) /lib # 共享库(如libc.so.6) /etc # 配置文件(如网络配置) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值