openwrt 是针对于嵌入式设备的精简版 Linux 系统。所以一些常规的 Linux 服务都没有,比如 systemd 等。
openwrt 是通过 init.d 来管理服务的。所有的服务都在 /etc/init.d
目录下。
对某个服务进行操作也很方便,例如对 network 服务:
# 启动 network
/etc/init.d/network start
# 重启 network
/etc/init.d/network restart
# 停止 network
/etc/init.d/network stop
如果需要某个服务开机自启动,可以 enable:
/etc/init.d/frp enable
会自动在 /etc/rc.d/
目录下建立一个链接指向 /etc/init.d
下的对应服务,如:S95frp。
S95 表示此服务的启动顺序,下面会做介绍。
基本结构
script 配置文件基本结构如下:
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=95
STOP=15
start_service() {
}
service_triggers() {
}
stop_service() {
}
restart_service() {
}
首先定义 shebang,定义脚本执行的相关依赖。
然后通过 USE_PROCD 定义我们的脚本是新的 procd 脚本而不是老版本的 init 脚本。
START=95 定义此服务开机启动时,其服务启动顺序序号。最大为 95,数字越大启动排序越靠后。
STOP=15 定义此服务在关机时,其服务关闭顺序序号。数字越小关闭排序越靠前。
Init script 有两个主要任务:
- 定义此服务的配置
- 定义何时重新配置此服务
每个服务都有各自特定需要执行的指令,他们都存储在 procd 内部。需要在 start_service()
中定义服务配置内容。
start_service
start_service()
的主要任务是:
- 启动一个服务需要执行的命令
- 监测某些信息的变化,如:文件或网络的变化
- 配置 procd 需要的设定,如:auto respawning, logging stdout
以上的任务作为一个服务实例状态存储在 procd 中。当特定的系统配置发生变化,会自动根据 trigger 的设定调用 start_service()
。
需要通过设定参数来配置服务实例,常用的参数是直接在 start_service 中设定,如 command,一般我么通过 procd_set_param()
和 procd_append_param()
来设定参数。
下面列举了支持的参数,有些需要设定有些可以省略:
start_service() {
procd_open_instance [instance_name] # 给服务实例定义一个名称
procd_set_param command /sbin/your_service_daemon -b -a --foo # 需要在前台被执行的服务
procd_append_param command -bar 42 # 给以上命令附加的指令参数
# 如果服务意外中止了,定义 redpawn 可以自动重启它,如果服务命令的确只需要运行一次,需要谨慎设定这里
# 如果进程在 respawn_threshold 定义的时间内结束了,则判定为进程崩溃并尝试重启它,尝试5次后会停止重启
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_set_param env SOME_VARIABLE=funtimes # 给进程传递环境变量
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 重启进程
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 # 转发 stdout 输出到 logd
procd_set_param stderr 1 # same for stderr
procd_set_param user nobody # 以 nobody 用户运行服务
procd_set_param pidfile /var/run/somefile.pid # 在服务启动时写入一个 pid 文件,在停止服务时删除此 pid 文件
procd_close_instance # 结束服务实例配置
}
当我们通过 start 参数执行这个脚本时,会自动运行 start_service()
:
/etc/init.d/test start
stop_service
如果需要在服务进程被终止时,执行特定的命令,可以在 stop_service()
中定义。如:
stop_service() {
kill $(ps | grep v2ray | awk '/-confdir/ {print $1}')
}
通过 stop 参数可以直接调用此 method:
/etc/init.d/test stop
restart_service
当我们想要重启某个服务,可以通过单独执行 stop 和 start 来实现,也可以直接定义一个 restart_service()
来自动完成这个过程:
restart_service() {
stop
start
}
注意,在脚本内部调用某个 function 只需要写它的前面的名称即可。
重启服务只需要运行以下命令即可:
/etc/init.d/test restart
service_triggers
可以定义当某个 event 被触发时,自动运行某个 function。
service_triggers()
{
procd_add_reload_trigger "<uci-file-name>" "<second-uci-file>"
procd_add_reload_interface_trigger <interface>
}
以上配置会在 luci 的配置文件发生修改时,自动触发 reload function。