OpenWrt开发必备软件模块——进程管理服务procd_openwrt procd 验证-程序员宅基地

技术标签: 软件模块之procd(reload_config、procd  OpenWrt开发  

一、procd简介

  • 通常的嵌入式系统均有一个守护进程,该守护进程监控系统进程的状态,如果某些系统进程异常退出,将再次启动这些进程。procd 就是这样一个进程,它是使用C语言编写 的,一个新的OpenWrt进程管理服务。
  • 它通过init脚本来将进程信息加入到procd的数据库中来管理进程启动,这是通过ubus总线调用来实现,可以防止进程的重复启动调用。

procd的进程管理功能主要包含3个部分

  • ①reload_config:检查配置文件是否发生变化,如果有变化则通知procd进程。
  • ②procd守护进程:接收使用者的请求,增加或删除所管理的进程,并监控进程的状态,如果发现进程退出,则再次启动进程。
  • ③procd.sh:提供函数封装procd提供系统总线方法,调用者可以非常便利的使用procd提供的方法。

二、reload_config

  • 工作原理:当在命令行执行reload_config时,会对系统中的所有配置文件生成MD5值,并且和应用程序使用的配置文件MD5值进行比较(对/var/run/config.md5文件进行比较),如果不同就通过ubus总线通知procd配置文件发生改变,如果应用程序在启动时,向procd注册了配置触发服务,那就将调用 reload函数重新读取配置文件,通常是进程退出再启动。如果配置文件没有改变将不会调用,这将节省系统CPU资源。
  • 两点注意事项
    • 注意:是配置文件的真实配置内容发生改变之后才会调用,如果增加空行和注释并不会引起配置文件的实质内容改变。
    • 系统启动时,会执行reload_config将初始配置文件摘要值保存为/var/run/config.md5文件中,下次再执行reload_config就是与这文件里面的MD5值进行比较的。

工作原理详解:

  • 我们以防火墙的配置文件发生改变为例来说明。
  • ①当手动执行reload_config时,首先将目录/etc/config目录下的所有文件通过“uci show”命令输出其配置到“/var/run/config.check” 目录下,这个命令将过滤配置文件增加空行和注释的情况。
  • ②初始系统启动时的配置文件摘要值保存在文件/var/run/config.md5 中,我们通过 “md5sum –c”命令来从文件中读取MD5值并验证是否和现有的配置文件MD5是否一致, 如果不一致则就调用ubus方法通知procd进程配置文件发生改变。
  • ③当procd知道配置文件发生改变后,procd就会调用/etc/init.d/firewall reload来处理配置文件改变,其他配置文件没有改变的进程,系统将不会花费资源进行处理。
  • ④最后将现在运行中的配置文件MD5值保存到/var/run/config.md5中。

三、procd进程

  • procd进程向ubus总线注册了service和system对象。

service对象

  • 下表是serveis对象提供的方法,主要有3部分功能:进程的管理、文件触发器(trigger)、配置验证服务(validate)。
方 法 含 义
set 进程如果存在,则修改已经注册的进程信息,如果不存在则增加,最后启动注册的进程
add 增加注册的进程
list 如果不带参数,则列出所有注册的进程和其信息
delete 删除指定服务进程,在结束进程时调用,例如停止防火墙会进行以下调用: ubus call service delete ‘{“name”:”firewall”}’
event 发出事件,例如 reload_config 就使用该方法来通知配置发生改变
validate 查看所有的验证服务
  • set方法:
    • 上面的3个功能都是通过set方法增加到procd保存的内存数据库中。数据库以服务名称作为其主键。
    • 共有5个参数:第一个参数为被管理的服务进程名称;第二个参数为启动脚本绝对路径;第三个参数为进程实例信息,例如可执行程序路径和进程的启动参数等;第四个参数为触发器;第五个参数为配置验证项(前3个参数是必须要传递的,后面两个参数可选)。
  • delete方法:
    • 在删除时使用 delete 方法。
    • 共有两个参数:第一个参数为服务名称,第二个参数为进程实例名称,可以不指定实例名称。
  • list方法:
    • 查询时使用 list 方法。
    • 共有两个参数:第一个参数为服务名称,第二个参数是布尔值,表示是否输出其详细信息,默认为不输出详细信息(该方法可以不带任何参数,表示查询所有注册的服务信息)。

  • 演示案例如下:
  • ①增加进程:如果hello进程需要procd来管理,那么我们使用ubus命令将hello进程加入的procd的内存数据库中。下面命令传递了4个参数,第一个参数设置被管理的服务进程名称为“hello”。第二个参数设置启动脚本绝对路径“/etc/init.d/hello”。第三个参数设置了进程实例信息,实例的启动命令为“/bin/hello”,启动参数为“-f -c bjbook.net”,并设置进程意外退出的重生参数(respawn)为默认值。第四个参数为触发器,收到文件“hello” 的“config.change”消息后执行脚本“/ect/init.d/hello”并传递“reload”参数。
ubus call service add '{"name":"hello", 
"script":"/etc/init.d/hello",
"instances":{"instance1":{ "command":["/bin/hello","-f","-c","bjbook.net"],"respawn":[ ] }},
"triggers": [ ["config.change",["if", ["eq","package", "hello" ], ["run_script","/ect/init.d/hello", "reload" ] ] ] ]
}'
  • ②删除进程:参数传递进程的名字即可。
ubus call service delete '{"name":"hello"}'
  • ③查看注册的进程信息:也可以不指定名称,将输出所有的管理列表。“verbose”为真,表示输出其详细信息。
ubus call service list '{"name":"hello","verbose":true}'
  • ④发送事件:第一个参数含义为事件类型,现在只支持“config.change”事件消息; 第二个参数表示文件“hello”,是指在目录“/etc/config”下的文件。在配置文件发生改变 时调用。通知 procd 进程配置文件 hello 发生了改变。
ubus call service event '{"type":"config.change","data":{"package":"hello"}}'

system对象

  • procd 注册在系统总线上的另外一个对象为system。
  • 下表为system 对象的所有方法。 该对象可以供luci来调用,其他模块很少调用,因此不再详述。
方 法 含 义
board 系统软硬件版本信息,包含 4 个部分,分别为内核版本、主机名称、系统 CPU 类 型信息和版本信息,版本信息从/etc/openwrt_release 文件读出
info 当前系统信息,包含 5 部分,分别为系统启动时间、系统当前时间、系统负载情况、 内存和交换分区占用情况等
upgrade 设置 service_update 为 1
watchdog 设置 watchdog 信息,还存在问题,例如如果本身为 0 的情况
signal 向指定 pid 的进程发信号,是通过 kill 函数来实现的
nandupgrade 执行升级

四、procd.sh

  • 使用ubus方法来进行管理时其传递参数复杂并且容易出错,procd.sh将这些参数拼接组织功能封装为函数,每一个需要被procd管理的进程都使用它提供的函数进行注册。

procd.sh的函数

  • 这些函数组织为JSON格式的消息然后通过ubus总线向procd进程发送消息。这些函数将不同功能封装为不同的函数,构建特定的JSON消息来表达特定的功能用法。
  • 函数命名规范:procd.sh提供的API命名非常规范,除了有一个uci_validate_section函数用于验证UCI 配置文件以外,其他所有的函数均是以“procd_”开头。

procd_open_ trigger、procd_close_trigger、procd_add_reload_trigger函数

  • procd_open_ trigger函数创建一个触发器数组,在增加了所有的触发器之后,调用procd_close_trigger函数来结束触发器数组的增加。
  • procd_add_reload_trigger:增加配置文件触发器,每次配置文件的修改,如果调用了reload_config时,当前实例都被重启。有一个可选的参数为配置文件名称。其实它在内部是调用 procd_open_trigger、procd_add_config_trigger 和 procd_close_trigger 这3个函数来增加触发器。

procd_open_instance、procd_set_param、procd_close_instance函数

  • 通常这3个函数在一起使用
  • procd_open_instance:开始增加一个服务实例。
  • procd_set_param:设置服务实例的参数值。通常会有以下几种类型的参数:(每次只能使用一种类型参数,其后是这个类型参数的值)。
    • command:服务的启动命令行。
    • respawn:进程意外退出的重启机制及策略,它需要有 3 个设置值。第一个设置为 判断异常失败边界值(threshold),默认为 3600 秒,如果小于这个时间退出,则 会累加重新启动次数,如果大于这个临界值,则将重启次数置 0。第二个设置为 重启延迟时间(timeout),将在多少秒后启动进程,默认为 5 秒。第三个设置是总 的失败重启次数(retry),是进程永久退出之前的重新启动次数,超过这个次数进 程退出之后将不会再启动。默认为 5 次。也可以不带任何设置,那这些设置都是 默认值。
    • env:进程的环境变量。
    • file:配置文件名,比较其文件内容是否改变。
    • netdev:绑定的网络设备(探测 ifindex 更改)。
    • limits:进程资源限制。
  • procd_close_instance:完成进程实例的增加。
  • 演示案例:下面为rpcd对procd函数的使用,这个示例可以用于大多数应用程序。PROG变量在前面已设置为/bin/rpcd。该示例将最终调用以下命令完成进程的增加。
ubus call service set '{"name":"rpcd", "script":"/etc/init.d/rpcd",
"instances": {"instance1":{ "command": ["/bin/rpcd"] } } }'
procd_open_instance
procd_set_param command "$PROG"
procd_close_instance

procd_open_validate、procd_close_validate函数

  • procd_open_validate:打开一个验证数组,是和 procd_close_validate 函数一起使用。
  • procd_close_validate:关闭一个验证数组。
  • 演示案例:下面是软件包firewall使用 procd 来对防火墙配置的触发器和验证。
procd_add_reload_trigger firewall

procd_open_validate
validate_firewall_redirect
validate_firewall_rule
procd_close_validate

procd_open_service(name, [script])、procd_close_service函数

  • procd_open_service(name, [script]):至少需要一个参数,第一个参数是实例名称, 第二个参数是可选参数为启动脚本。该函数仅在在 rc.common 中调用,用于创建一个新的 procd 进程服务消息。
  • procd_close_service:该函数不需要参数,仅在 rc.common 中调用,完成进程管理服务的增加。

procd_kill函数

  • 杀掉服务实例(或所有的服务实例)。至少需要一个参数,第一个参 数是服务名称,通常为进程名,第二个是可选参数,是进程实例名称,因为可能有多个进 程示例,如果不指定所有的实例将被关闭。该函数在 rc.common 中调用,用户从命令行调 用 stop 函数时会使用该函数杀掉进程。

uci_validate_section

  • 调用 validate_data 命令注册为验证服务。在配置发生改变 后对配置文件的配置项合法性进行校验。验证服务是在进程启动时通过 ubus 总线注册到 procd 进程中。
  • 输入以下命令,可以看到系统所有注册的验证服务。
ubus call service validate

  • 这些验证服务是在启动脚本中增加验证服务来实现,如下代码所示,service_triggers 函数是预定义好的回调函数,在每一个增加服务结束后会自动调用,使用者不必关注如何 调用。validate_cron_section 函数是真正的将验证服务加入 procd 的验证服务中。它调用 uci_validate_section 函数,而 uci_validate_section 函数进一步调用 validate_data 程序。
validate_cron_section() {
    uci_validate_section system system "${1}" \
    'cronloglevel:uinteger'
}

service_triggers()
{
    procd_add_validation validate_cron_section
    procd_add_reload_trigger "hello"
}

五、rc.common

  • rc.common在1209及之前的版本中并不支持procd启动,在1407版本中增加了专门针对procd的启动,该脚本向前兼容。
  • USE_PROCD变量:
    • 在软件模块的启动脚本中如果没有定义USE_PROCD变量:则启动流程和之前完全相同。
    • 如果定义了 USE_PROCD变量:对start、stop 和 reload函数进行重新定义,在调用这些函数时,将调用start_service、stop_service和 reload_service函数等。
  • procd预定义的函数如下:如果在自己的启动脚本中定义了USE_PROCD那就调用这些函数。在rc.common中重新定义了start函数,相当于重载了这些函数。
函 数 含 义
start_service 向 procd 注册并启动服务,是将在 services 所管理对象里面增加了一项。
stop_service 让 procd 解除注册,并关闭服务, 是将在 services 中的管理对象删除。
service_triggers 配置文件或网络接口改变之后触发服务重新读取配置。
service_running 查询服务的状态。
reload_service 重启服务,如果定义了该函数,在 reload 时将调用该函数,否则再次调用 start 函数。
service_started 用于判断进程是否启动成功。

六、编写一个procd启动脚本

#!/bin/sh /etc/rc.common

USE_PROCD=1
START=15
STOP=85
PROG=/bin/hello

validate_hello_section()
{
	uci_validate_section hello system globe \
	'delay:uinteger(1:200)' 
}

start_service() {
	echo "start HelloRoute!"
	validate_hello_section || {
	echo "hello validattion failed!"
	return 1
	}

	procd_open_instance
	procd_set_param command "$PROG" –f -w bjbook.net
	procd_set_param respawn
	procd_close_instance
}

service_triggers()
{
	procd_add_reload_trigger "hello"
}

reload_service()
{
	stop
	start
}
  • 备注: 在执行该启动脚本时,如果需要对procd脚本进行调试,可以设置PROCD_DEBUG变量为 1,这样可以输出向ubus总线调用的参数信息。例如:
PROCD_DEBUG=1 /etc/init.d/hello start

脚本分析

  • 通常前面两行内容是固定的,第一行表示使用“/etc/rc.common”来解释脚本。第二行内容设置USE_PROCD变量为1,表示使用procd来管理进程。

  • PROG变量用来给程序的启动脚本赋值,用于启动应用程序。

  • validate_hello_section函数:验证了配置文件hello中的delay变量否为整型值,并且在合理的(1~200)范围内。

  • start_service函数:负责程序的启动。
    • 函数开始处调用了validate_hello_section函数对程序配置文件进行验证,如果验证失败,则进程不启动。
    • 在参数验证完成后,调用procd_open_instance 数发起实例增加,接着调用了procd_set_param函数来设置了启动命令和启动参数,再接着设置其进程意外退出的重启机制及策略为默认值,最后调用procd_close_instance函数完成实例的增加。注意procd管理的进程需要运行在前台,即不能调用daemon或类似函数。

  • service_triggers函数:增加触发器,我们增加了对配置文件hello的触发服务。当hello文件发生改变后,如果调用了 reload_config命令,将触发调用reload_service函数。

  • reload_service函数:在传递reload参数时进行调用,如果没有该函数,将会调用默认start函数。


  • 我是小董,V公众点击"笔记白嫖"解锁更多OpenWrt资料内容。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41453285/article/details/102622557

智能推荐

转贴:win2008改造成准VISTA-程序员宅基地

文章浏览阅读123次。安装WINDOWS SERVER 2008前请确认你已经做好了以下准备:1.你的硬件必须满足下列要求处理器:最小: 1GHz 建议: 2GHz 最佳: 3GHz 或者更快速的内存: 最小: 512MB RAM建议: 1GB RAM最佳: 2GB RAM (完整安装) 或者 1GB RAM (Server Core 安装) 或者最大 (32位系统 ): 4GB (标准版) 或..._net framework 3.0支持开vista玻璃效果吗

【正一专栏】巴萨四大皆空怎么办_巴萨14年四大皆空-程序员宅基地

文章浏览阅读2.5k次。巴萨四大皆空怎么办每年的四月对于双线作战的球队来说都是决定命运的时刻,巴萨神奇逆转大巴黎后不得不在欧冠面临着尤文图斯的挑战,而在国内联赛又要紧追领头羊皇马。一个月要踢9场比赛,基本上都是一周双赛。巴萨上周刚刚在联赛中输球,错失了反超皇马的机会,而今天凌晨的欧冠比赛,巴萨0:3惨败给尤文图斯,欧冠晋级之路前景黯淡、又只能期待奇迹。没了联赛和欧冠,巴萨就会四大皆空,恩里克只能黯然走_巴萨14年四大皆空

苹果系统使用linux内核,iOS操作系统是不是基于Linux呢?-程序员宅基地

文章浏览阅读5.2k次。iOS实际上是Darwin的ARM变体,源自BSD,类UNIX内核,以及Apple自己的Mach内核扩展系统。这与是完全不同的,Linux是一个单片内核,这意味着所有驱动程序代码和I / O工具包都是核心内核的一部分。Apple是一个混合内核。有些人住在内核中,有些是内核扩展(通常是.kext文件)。相比之下,Windows是一个微内核,意味着内核中的内容很少,而且几乎所有东西都是外部驱动程序。L..._苹果的ios系统是linux内核吗?

WEEX框架(一)框架简介和快速上手体验-程序员宅基地

文章浏览阅读8.6k次。框架简介Weex,是能够完美兼顾性能与动态性,让移动开发者通过简捷的前端语法写出Native级别的性能体验的框架,并支持iOS、安卓、Web等多端部署,由阿里巴巴研发和维护。对于移动开发者来说,Weex主要解决了频繁发版和多端研发两大痛点,同时解决了前端语言性能差和显示效果受限的问题。开发者只需要在自己的APP中嵌入Weex的SDK,就可以通过撰写HTML/CSS/JavaScript来开发Native级别的Weex界面。Weex界面的生成码其实就是一段很小的JS,可以像发布网页一样轻松部署在服务端,_weex框架

【工具使用系列】关于MATLAB for mac 运行时崩溃故障的解决方法_matlab_crash_dump-程序员宅基地

文章浏览阅读1.1w次。MATLAB 常见问题的解决方案1. MATLAB for mac使用过程中,突然崩溃……_matlab_crash_dump

PTA 5-10 多项式A除以B (2017cccc初赛L2-2)_pta你需要计算两个多项式相除的商q和余r,其中r的阶数必须小于b的阶数-程序员宅基地

文章浏览阅读2.7k次,点赞4次,收藏3次。5-10多项式A除以B(25分)这仍然是一道关于A/B的题,只不过A和B都换成了多项式。你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数。输入格式:输入分两行,每行给出一个非零多项式,先给出A,再给出B。每行的格式如下:N e[1] c[1] ... e[N] c[N]其中N是该多项式非零项的个数,e[i]是第i个非零项的指数,c_pta你需要计算两个多项式相除的商q和余r,其中r的阶数必须小于b的阶数

随便推点

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:1-程序员宅基地

文章浏览阅读4.5k次,点赞3次,收藏8次。一、了解nn.DataParallelhttps://zhuanlan.zhihu.com/p/102697821二、报错的几种原因2.1 cuda:0 and cpu!简单的将没有转移到gpu的参数转移即可。例如,xx.to("cuda")2.2 cuda:1 and cuda:0!可能存在有一些参数,不能使用nn.DataParallel自动分配到多个gpu。检查是否有自定义的tensor,注意:不能是Variable,必须是Parameter。..._on the same device, but found at least two devices, cuda:1

数组的两种传递方式_数组传递-程序员宅基地

文章浏览阅读1.3w次,点赞7次,收藏45次。 数组传递:将数组作为参数传递给函数,分值传递和地址传递。其中,值传递的效率较低,不建议使用。两种传递方式都会改变main函数中数组的值,如下代码中a[3]的结果都为6。注意区分数组的值传递和函数值传递的区别。//数组的两种传递方式#include<iostream>using namespace std;//值传递void fun1(int a[5]){ ..._数组传递

html点击按钮跳转到另一个界面_网页制作:一个简易美观的登录界面-程序员宅基地

文章浏览阅读2.2w次,点赞62次,收藏449次。效果图目录结构:在我们做一个页面之前,要先想好他的一个整体布局,也就是我们这里面的login.html主页面,大致结构如下:接下来,我们先上代码,看一下具体实现方法:login.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>..._html table登陆界面带有页面转换

C语言彩色版贪吃蛇——图形界面Easyx的简单使用_c easyx实现登录-程序员宅基地

文章浏览阅读2w次,点赞40次,收藏237次。大一上大概12月份学完了C语言,基本语法与知识已经基本具备,可以用C语言写出基本的贪吃蛇游戏,但是基础C语言的可视化与交互功能实在是太弱了,为了写出有色彩的游戏,需要在网上安装一个Easyx的插件,具体Easyx如何使用参见https://zhuanlan.zhihu.com/p/24826034点击打开链接然后编程软件我用的是VS 2017(因为Dev C++不支持Easyx) VS安装入口_c easyx实现登录

全球公链进展| Shibarium已上线;opBNB测试网PreContract硬分叉;Sui 主网 V1.7.1 版本_shibarium上线-程序员宅基地

文章浏览阅读1.6k次。Sui 主网现已升级至 V1.7.1 版本,此升级包含了多项修复和优化,包括:协议版本提升至 20 版本,在 Sui 框架中新增 Kiosk Extensions API 和一个新的 sui::kiosk_extension 模块,开发者可使用该 API 构建自定义的 Kiosk 应用程序,以扩展 Kiosk 基本功能;以太坊基金会工程师 Parithosh Jayathi 发推称,Dencun-devnet-8 已上线,这是开发者网络的最新迭代版本,旨在允许客户端与最新规范进行互操作性测试。_shibarium上线

idea显示properties文件中文乱码_idea properties 乱码-程序员宅基地

文章浏览阅读1k次。解决idea显示文件中文乱码在项目中通常会遇到如下问题,突然properties文件中文就显示为\u5730等等这样类似的字符。_idea properties 乱码

推荐文章

热门文章

相关标签