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