OpenWrt的开机启动服务(init scripts)
SysV风格的init启动
参考 https://wiki.openwrt.org/doc/techref/initscripts
以一个简单的例子来说明
#!/bin/sh /etc/rc.common # Example script # Copyright (C) 2007 OpenWrt.org START=10 STOP=15 start() { echo start # commands to launch application } stop() { echo stop # commands to kill application }
第一行shebang #! 使用 /bin/sh /etc/rc.common 作为脚本解释器并在执行脚本前调用 main 和检查脚本
公用的 init script 方法有
start # 启动服务 stop # 停止服务 restart # 重启服务 reload # 重新载入配置文件, 如果失败则重启 enable # 启用开机自启动, 实际上是在/etc/rc.d/下创建S??和K??开头的软链 disable # 禁用开机自启动, 实际上是删除/etc/rc.d/下对应的软链
脚本中 start() 和 stop() 是必须的
启动顺序
START= 和 STOP= 决定脚本启动时的次序. 启动时init.d会根据文件名顺序, 自动执行在/etc/rc.d中找到的脚本. 初始化脚本可以作为/etc/init.d/下文件的软链放置在/etc/rc.d/.
enable 和 disable 可以自动帮你创建对应的带序号的软链.
这个例子中START=10 会被链接到 /etc/rc.d/S10example, 启动时执行在START=9之后, 在START=11之前. 而STOP=15会被链接到 /etc/rc.d/K15example, 执行在STOP=14之后, 在STOP=16之前. 同一个启动数字的, 按字母顺序启动.
脚本中的 boot()
当存在boot()方法时, 系统启动时会调用boot()而不是start()
boot() { echo boot # commands to run on boot }
你可以使用EXTRA_COMMANDS和EXTRA_HELP设置自定义的服务方法
EXTRA_COMMANDS="custom" EXTRA_HELP=" custom Help for the custom command" custom() { echo "custom command" # do your custom stuff }
多个自定义方法的添加
EXTRA_COMMANDS="custom1 custom2 custom3" EXTRA_HELP=<<EOF custom1 Help for the custom1 command custom2 Help for the custom2 command custom3 Help for the custom3 command EOF custom1 () { echo "custom1" # do the stuff for custom1 } custom2 () { echo "custom2" # do the stuff for custom2 } custom3 () { echo "custom3" # do the stuff for custom3 }
快速查询所有服务的自启动状态, 可以使用以下命令
root@OpenWrt:~# for F in /etc/init.d/* ; do $F enabled && echo $F on || echo $F **disabled**; done /etc/init.d/boot on /etc/init.d/bootcount on /etc/init.d/cron on /etc/init.d/dnsmasq on /etc/init.d/done on /etc/init.d/dropbear on /etc/init.d/firewall on /etc/init.d/fstab on /etc/init.d/gpio_switch on /etc/init.d/led on /etc/init.d/log on /etc/init.d/network on /etc/init.d/odhcpd on /etc/init.d/rpcd on /etc/init.d/samba on /etc/init.d/ss-libev on /etc/init.d/sysctl on /etc/init.d/sysfixtime on /etc/init.d/sysntpd on /etc/init.d/system on /etc/init.d/transmission on /etc/init.d/uhttpd on /etc/init.d/umount **disabled** /etc/init.d/wifidog **disabled**
procd风格的init启动
procd init脚本与sysv风格的启动脚本区别在于
- procd方式下, 服务必须以前台方式运行
- 不同的shebang line: #!/bin/sh /etc/rc.common
- 指定procd方式的声明 USE_PROCD=1
例如
#!/bin/sh /etc/rc.common USE_PROCD=1
脚本格式说明
#!/bin/sh /etc/rc.common # Copyright (C) 2008 OpenWrt.org # 启动的顺序,越大越靠后 START=98 # 停止的顺序, 越小越靠前 STOP=15 # 声明使用procd USE_PROCD=1 BINLOADER_BIN="/usr/bin/binloader" # start_service 函数必须要定义 start_service() { # 创建一个实例, 在procd看来一个应用程序可以多个实例 # ubus call service list 可以查看实例 procd_open_instance # 告知procd当binloader程序退出后尝试进行重启 procd_set_param respawn # binloader执行的命令是"/usr/bin/binloader", 若后面有参数可以直接在后面加上 procd_set_param command "$BINLOADER_BIN" # 关闭实例 procd_close_instance } # 定义退出服务器后需要做的操作 stop_service() { rm -f /var/run/binloader.pid } reload_service() { procd_send_signal clash } restart() { stop start }
常用的start_service()语句
start_service() { procd_open_instance [instance_name] procd_set_param command /sbin/your_service_daemon -b -a --foo # service executable that has to run in **foreground**. procd_append_param command -bar 42 # append command parameters # respawn automatically if something died, be careful if you have an alternative process supervisor # if process dies sooner than respawn_threshold, it is considered crashed and after 5 retries the service is stopped procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} procd_set_param env SOME_VARIABLE=funtimes # pass environment variables to your process procd_set_param limits core="unlimited" # If you need to set ulimit for your process procd_set_param file /var/etc/your_service.conf # /etc/init.d/your_service reload will restart the daemon if these files have changed procd_set_param netdev dev # likewise, except if dev's ifindex changes. procd_set_param data name=value ... # likewise, except if this data changes. procd_set_param stdout 1 # forward stdout of the command to logd procd_set_param stderr 1 # same for stderr procd_set_param user nobody # run service as user nobody procd_set_param pidfile /var/run/somefile.pid # write a pid file on instance start and remove it on stop procd_close_instance }
被procd执行的程序不能是daemon后台程序,因为后台程序的主进程退出后在procd看来就是程序退出了,然后会进入respawn流程,之后重复启动和退出, 最后失败:
procd: Instance binloader::instance1 s in a crash loop 6 crashes, 0 seconds since last crash
参考
https://oldwiki.archive.openwrt.org/inbox/procd-init-scripts
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体