前言

  刚进公司的时候,所接触到的产品使用的是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