openwrt 启动脚本

传统SysV风格启动脚本):

创建并编辑run_hello脚本

  • /etc/init.d/run_hello
bash 复制代码
#!/bin/sh /etc/rc.common
# OpenWRT.org

START=95
STOP=05

start() {
	echo "running hello start."
}

stop() {
	echo "running hello stop."
}

restart() {
	echo "running hello restart."
}

reload() {
	echo "running hello reload."
}

help() {
	echo "running hello help."
}

传统SysV风格示例2:

bash 复制代码
#!/bin/sh /etc/rc.common

START=90
STOP=10

# 额外命令
EXTRA_COMMANDS="status test reload"
EXTRA_HELP="    status  Show service status
    test    Test configuration
    reload  Reload configuration"

# 启动
start() {
    echo "Starting service"
    
    # 使用 start-stop-daemon
    start-stop-daemon -S -b -m \
        -p /var/run/myservice.pid \
        -x /usr/sbin/myservice \
        -- --daemon --config /etc/myservice.conf
    
    return $?
}

# 停止
stop() {
    echo "Stopping service"
    
    start-stop-daemon -K \
        -p /var/run/myservice.pid \
        -x /usr/sbin/myservice
    
    [ -f /var/run/myservice.pid ] && rm -f /var/run/myservice.pid
    
    return $?
}

# 重启
restart() {
    stop
    sleep 1
    start
}

# 重新加载
reload() {
    echo "Reloading configuration"
    
    [ -f /var/run/myservice.pid ] && {
        kill -HUP $(cat /var/run/myservice.pid)
        echo "Configuration reloaded"
    } || {
        echo "Service not running"
        return 1
    }
}

# 状态检查
status() {
    if [ -f /var/run/myservice.pid ]; then
        local pid=$(cat /var/run/myservice.pid)
        if kill -0 "$pid" 2>/dev/null; then
            echo "Service is running (PID: $pid)"
            return 0
        else
            echo "Service is not running (stale PID file)"
            rm -f /var/run/myservice.pid
            return 1
        fi
    else
        echo "Service is not running"
        return 3
    fi
}

# 配置测试
test() {
    echo "Testing configuration"
    
    # 验证配置文件
    /usr/sbin/myservice --test --config /etc/myservice.conf
    
    return $?
}

基于procd风格

  • OpenWrt 的启动脚本基于 BusyBox init 系统,结合 procd 进程管理框架,提供了一套标准的启动脚本规范。
  • OpenWrt的启动脚本遵循LSB(Linux Standard Base)init脚本的规范,但使用自己的procd进程管理工具(可选)来管理服务。
  • 一个典型的OpenWrt启动脚本位于/etc/init.d/目录下,其基本结构如下:
    1. 脚本开头使用shebang指定解释器:#!/bin/sh /etc/rc.common
    2. 使用/etc/rc.common提供的函数
    3. 定义START和STOP变量,表示启动和停止的顺序
    4. 可选地使用USE_PROCD=1来启用procd
    5. 定义启动、停止、重启等函数

启动脚本的安装与使用

启动脚本需要可执行权限。安装后,可以使用以下命令来管理服务:

/etc/init.d/script start

/etc/init.d/script stop

/etc/init.d/script restart

/etc/init.d/script reload

/etc/init.d/script enable

/etc/init.d/script disable

其中,enable和disable用于设置服务是否在启动时自动启动。实际上,enable命令会在/etc/rc.d/目录下创建一个指向/etc/init.d/脚本的符号链接,而disable则删除这个链接。

基本脚本结构

最小启动脚本示例:

bash 复制代码
#!/bin/sh /etc/rc.common

START=95
STOP=05
USE_PROCD=1

start_service() {
    procd_open_instance
    procd_set_param command /usr/bin/my_service_command
    procd_append_param command --my-argument 123

    procd_set_param respawn
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}

stop_service() {
    # 如果停止服务需要额外的操作,可以在这里定义
    # 否则,procd会自动停止服务
}

启动顺序控制

  • 标准启动顺序(启动数字范围:1-99)

    • 1-20: 内核和系统初始化
    • 21-40: 基础服务 (network, firewall)
    • 41-60: 系统服务 (dns, dhcp)
    • 61-80: 应用服务 (web, file sharing)
    • 81-99: 用户应用
  • 常见服务的 START 值:

    • sysctl: 10
    • network: 20
    • firewall: 40
    • dnsmasq: 50
    • uhttpd: 80
    • cron: 90
    • 自定义服务: 95-99
  • 注意事项:

    • 启动脚本的顺序:START和STOP变量的值决定了启动和停止的顺序。注意,启动顺序是从小到大,停止顺序是从小到大(即数字越小,在启动时越早执行,停止时也越早执行,但通常停止顺序与启动顺序相反)。

脚本的调试:如果脚本有问题,可以查看系统日志(使用logread命令)来获取错误信息。

procd进程管理

启用procd : USE_PROCD=1

bash 复制代码
# 服务启动(procd 风格)
start_service() {
    procd_open_instance
    
    # 命令和参数
    procd_set_param command /usr/sbin/myservice
    procd_append_param command --config /etc/myservice.conf
    procd_append_param command --log /var/log/myservice.log
    
    # 运行用户和组
    procd_set_param user nobody
    procd_set_param group nogroup
    
    # 标准输出/错误
    procd_set_param stdout 1
    procd_set_param stderr 1
    
    # PID 文件
    procd_set_param pidfile /var/run/myservice.pid
    
    # 进程监控和重启
    procd_set_param respawn
    procd_set_param respawn_retry 3600 5 5
    # 3600秒内重启5次后放弃,重启间隔5秒
    
    # 环境变量
    procd_set_param env LANG=C
    procd_set_param env HOME=/tmp
    
    # 资源限制
    procd_set_param limits core="unlimited"
    procd_set_param limits nofile="1024"
    
    # 优先级
    procd_set_param nice -10
    
    procd_close_instance
}

# 服务停止(可选,默认会自动停止)
stop_service() {
    # 自定义停止逻辑
    echo "Custom stop operations"
    [ -f /var/run/myservice.pid ] && {
        kill $(cat /var/run/myservice.pid)
        rm -f /var/run/myservice.pid
    }
}

# 重新加载配置
reload_service() {
    # 发送 HUP 信号重新加载配置
    [ -f /var/run/myservice.pid ] && {
        kill -HUP $(cat /var/run/myservice.pid)
    }
}

# 配置变化触发器
service_triggers() {
    # 配置文件变化时重载
    procd_add_reload_trigger /etc/config/myservice
    
    # 网络接口变化时重载
    procd_add_interface_trigger "network.interface.*" /etc/init.d/myservice reload
    
    # 无线接口变化时重载
    procd_add_wifi_trigger "wireless.radio.*" /etc/init.d/myservice restart
}

procd_set_param 参数详解

参数 说明 示例
command 主命令 procd_set_param command /usr/bin/nginx
append_param 追加参数 procd_append_param command -g "daemon off;"
user 运行用户 procd_set_param user nobody
group 运行组 procd_set_param group nogroup
pidfile PID文件 procd_set_param pidfile /var/run/nginx.pid
stdout 标准输出 procd_set_param stdout 1(1=启用)
stderr 标准错误 procd_set_param stderr 1(1=启用)
respawn 自动重启 procd_set_param respawn
respawn_retry 重启策略 procd_set_param respawn_retry 3600 5 5
env 环境变量 procd_set_param env PATH=/bin:/sbin
nice 优先级 procd_set_param nice -10
limits 资源限制 procd_set_param limits nofile="1024"
umask 文件掩码 procd_set_param umask 022
netdev 网络设备 procd_set_param netdev eth0
file 文件描述符 procd_set_param file /var/etc/nginx.conf
watch 监控资源 procd_set_param watch network.interface.lan
error 错误处理 procd_set_param error /dev/console

脚本位置与命名

位置:/etc/init.d/(运行时)和 files/etc/init.d/(开发时)

命名:小写字母,通常与服务名称相同,如network、firewall

依赖关系控制

bash 复制代码
# 在脚本开头定义依赖
REQUIRES="network"
PROVIDES="myservice"
NEEDS="network.interface"

# 在 start() 中检查依赖
start() {
    # 检查网络是否就绪
    /etc/init.d/network enabled || {
        echo "Network service is required"
        return 1
    }
    
    # 检查端口是否可用
    if netstat -tln | grep -q ":8080 "; then
        echo "Port 8080 is already in use"
        return 1
    fi
}

示例:读取UCI配置

bash 复制代码
#!/bin/sh /etc/rc.common
# UCI 配置集成示例

USE_PROCD=1
START=90
STOP=10

# 加载 UCI 配置
load_config() {
    config_load myservice
    config_get_bool enabled "$1" enabled
    config_get port "$1" port
    config_get log_level "$1" log_level
    config_get interface "$1" interface
}

# 启动服务
start_service() {
    # 加载配置
    config_load myservice
    config_foreach load_config myservice
    
    # 检查是否启用
    [ "$enabled" = "1" ] || {
        echo "Service is disabled in UCI config"
        return 0
    }
    
    procd_open_instance
    
    procd_set_param command /usr/sbin/myservice
    procd_append_param command --port "$port"
    procd_append_param command --log-level "$log_level"
    
    # 网络接口
    [ -n "$interface" ] && procd_set_param netdev "$interface"
    
    procd_set_param respawn
    procd_close_instance
}

# 配置变化处理
service_triggers() {
    procd_add_reload_trigger myservice
}
相关推荐
小旺不正经2 小时前
n8n简介
linux·运维·服务器
阳光九叶草LXGZXJ3 小时前
达梦数据库-学习-43-定时备份模式和删除备份(Python+Crontab)
linux·运维·开发语言·数据库·python·学习
首席拯救HMI官3 小时前
【拯救HMI】HMI容错设计:如何减少操作失误并快速纠错?
大数据·运维·前端·javascript·网络·学习
RedKali3 小时前
Kali Linux自定义终端美化:初级-普通中级-root高级
linux
zl_dfq3 小时前
Linux 之 【文件】(重定向、一切皆文件的理解)
linux
HIT_Weston3 小时前
99、【Ubuntu】【Hugo】搭建私人博客:搜索功能(三)
linux·运维·ubuntu
txinyu的博客3 小时前
select/poll/epoll
linux·c++
小蜗的房子3 小时前
Oracle 19c RAC重建AWR步骤详解
linux·运维·数据库·sql·oracle·操作系统·oracle rac