• 嵌入式Linux设置开机自动运行程序(基于BusyBox init)


    目的

    开机自动运行程序,或者说系统启动时自动运行程序,这是经常会需要用到的功能。这个功能通常依托于 init 程序实现。 init 是Linux在内核启动完成之后第一个启动的程序,该程序会运行一些特定位置的脚本,相当于实现开机运行程序的效果。

    在常见的Linux发行版中 init 程序主要为 SysVinitSystemd 。在嵌入式Linux中根文件系统通常使用 buildroot 来建立, buildroot 默认是基于 BusyBox 构建根文件系统的,这种方式下默认的 init 程序可以称其为 BusyBox init 。 这篇文章将介绍通过 BusyBox init 实现开机自动运行程序的功能。

    BusyBox init启动流程

    inittab

    BusyBox init 会在启动后读取 /etc/ 目录下的 inittab 文件,下面是其内容样式:

    # /etc/inittab
    #
    # Copyright (C) 2001 Erik Andersen 
    #
    # Note: BusyBox init doesn't support runlevels.  The runlevels field is
    # completely ignored by BusyBox init. If you want runlevels, use
    # sysvinit.
    #
    # Format for each entry: :::
    #
    # id        == tty to run on, or empty for /dev/console
    # runlevels == ignored
    # action    == one of sysinit, respawn, askfirst, wait, and once
    # process   == program to run
    
    # Startup the system
    ::sysinit:/bin/mount -t proc proc /proc
    ::sysinit:/bin/mount -o remount,rw /
    ::sysinit:/bin/mkdir -p /dev/pts /dev/shm
    ::sysinit:/bin/mount -a
    ::sysinit:/bin/mkdir -p /run/lock/subsys
    ::sysinit:/sbin/swapon -a
    null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
    null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
    null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
    null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
    ::sysinit:/bin/hostname -F /etc/hostname
    # now run any rc scripts
    ::sysinit:/etc/init.d/rcS
    
    # Put a getty on the serial port
    console::respawn:/sbin/getty -L  console 0 vt100 # GENERIC_SERIAL
    
    # Stuff to do for the 3-finger salute
    #::ctrlaltdel:/sbin/reboot
    
    # Stuff to do before rebooting
    ::shutdown:/etc/init.d/rcK
    ::shutdown:/sbin/swapoff -a
    ::shutdown:/bin/umount -a -r
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    可以从注释中看到这个文件记录的是一条条按照一定规则编写的语句。

    BusyBox init 会在启动后执行第三个字段为 sysinit 的语句中的命令,会在关机时执行第三个字段为 shutdown 的语句中的命令。

    在这里添加语句就可以实现开机运行程序了,不过一般不推荐这么做。

    rcS 和 rcK

    从上面文件中可以看到 sysinit 系列的语句最后一条会去执行 /etc/init.d/ 目录下的 rcS 脚本,也即开机时其它工作完成后会执行 rcS 这个脚本。同样的会在关机时先执行 /etc/init.d/ 目录下的 rcK 脚本。这两个脚本内容如下:

    rcS

    #!/bin/sh
    
    
    # Start all init scripts in /etc/init.d
    # executing them in numerical order.
    #
    for i in /etc/init.d/S??* ;do
    
         # Ignore dangling symlinks (if any).
         [ ! -f "$i" ] && continue
    
         case "$i" in
            *.sh)
                # Source shell script for speed.
                (
                    trap - INT QUIT TSTP
                    set start
                    . $i
                )
                ;;
            *)
                # No sh extension, so fork subprocess.
                $i start
                ;;
        esac
    done
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    rcK

    #!/bin/sh
    
    
    # Stop all init scripts in /etc/init.d
    # executing them in reversed numerical order.
    #
    for i in $(ls -r /etc/init.d/S??*) ;do
    
         # Ignore dangling symlinks (if any).
         [ ! -f "$i" ] && continue
    
         case "$i" in
            *.sh)
                # Source shell script for speed.
                (
                    trap - INT QUIT TSTP
                    set stop
                    . $i
                )
                ;;
            *)
                # No sh extension, so fork subprocess.
                $i stop
                ;;
        esac
    done
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    可以看到 rcS 脚本会依据文件名排序依次读取 /etc/init.d/ 目录下名字为 S??* 格式的脚本文件,并执行其中的 start 方法。同用的 rcK 脚本会依据文件名逆排序读取 /etc/init.d/ 目录下名字为 S??* 格式的脚本文件,并执行其中的 stop 方法。

    设置开机自动运行程序

    对于我们需要设置开机运行程序而言,可以编写名字为 S??* 格式的脚本文件存放到 /etc/init.d/ 目录下,这样它就会在开机时被调用执行其中的 start 方法了。

    名字为 S??* 格式的脚本文件默认在 /etc/init.d/ 目录下已经有一些了:
    在这里插入图片描述

    我们可以参考它们来编写自己的脚本开机脚本,这里创建名为 S77test 的文件,其中内容如下:

    #!/bin/sh
    
    umask 077
    
    start() {
            echo "Starting test log: Naisu is coming!!!"
    }
    
    stop() {
            echo "Stopping test log: Naisu is leaving!!!"
    }
    
    restart() {
            stop
            start
    }
    
    case "$1" in
      start)
            start
            ;;
      stop)
            stop
            ;;
      restart|reload)
            restart
            ;;
      *)
            echo "Usage: $0 {start|stop|restart}"
            exit 1
    esac
    
    exit $?
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    备注1:各个函数中不建议出现长时间阻塞的操作,如果有需求建议在命令后面加上 (空格)& 放到后台运行;
    备注2:行尾必须是以只有换行符形式,不能是windows上回车加换行的形式;

    调整脚本权限:

    chmod 755 /etc/init.d/S77test
    
    • 1

    下面就是脚本在开关机时运行的演示了:
    在这里插入图片描述

    总结

    在使用 BusyBox init 的嵌入式Linux系统中设置开机自动运行程序并不复杂,只要了解其脚本调用流程基本就可以了。

  • 相关阅读:
    20231024后端研发面经整理
    Vue | Vue.js 基础 模版语法
    C生万物 | 从浅入深理解指针【最后部分】
    百度松果 买礼物(贪心)
    Navicat 强大的数据模型功能 | 面向数据库设计、架构和数据资产梳理等使用场景
    LeetCode 110平衡二叉树 257.二叉树的所有路径 404左叶子之和
    AJAX初
    redis-实现限流
    蒙特卡洛估计举例
    Node的模块化管理、Node的module对象、require命令、Buffer对象
  • 原文地址:https://blog.csdn.net/Naisu_kun/article/details/126637017