- 接下来几篇文章首先讲述 UCI 配置及配置接口,接着讲述系统内核设置,最后还会讲述一些非 UCI 系统配置,这些配置通常不提供用户修改接口,但在系统运行时也是非常重要的。
- MVC(Model-View-Control)模式是经典的Web开发编程模式,OpenWrt也采用该设 计模式。该设计模式为分层设计,模型层负责数据的持久化操作。OpenWrt 的模型层采用 统一配置接口(Unified Configuration Interface,UCI)。
- 统一配置接口(Unified Configuration Interface,UCI),是OpenWrt成功的关键技 术之一,已经移植支持数千个软件。它采用纯文本文件来保存配置,并提供命令 行和 C 语言编程调用接口进行管理。
- UCI的目的在于集中OpenWrt系统的配置。这样每一个开发人员只需学习一次即可, 减少了学习成本。这是 OpenWrt 成功的关键原因之一。它成功地应用于 OpenWrt 的 WhiteRussian 之后的系列版本。
- UCI 可以看作OpenWrt系统中最重要系统设置的主要配置接口。通常情况下这些设置对设备的功能运转至关重要,例如网络接口的配置、DHCP 和防火墙设置等。
- 配置节(section),是UCI配置的一个独立配置单元。UCI配置文件是由一个或多个配置节组成。配置节有一个配置类型属性,是以“config”开头,并且有一个可选名称。配置节包含一个或多个配置选项语句。
- 格式:配置文件由配置节(section)组成,配置节由多个“name/values”选项对(option)组成。
- 注意事项:
- 每一个配置节(section)都需要有一个类型标识(type),但不一定需要名称(name)。
- 每一个选项对(option)都有名称(name)和值(value),写在其所属于的配置节中。
- UCI标识符和配置文件的名称只能包含字母 a~z、0~9 和_。例如连字符(-)是不允许的。
- 选项的值可以包含任何字符,但需要将它们正确地加上引号。
- 没有名称标识的配置节称为匿名配置节。
- 类型(type)和选项(option)的含义均由应用程序来决定,类型一般用于应用程序决定如何处理配置节包含的配置选项。
- 如果一个选项(type)是不存在的并且是必需的,那应用程序通常会触发一个异常或者记录一个异常的日志,然后程序退出。
- 通常选项(option)在配置文件中都是使用空格或制表符缩进来标识,但这个并非是语法要求,仅仅是为了增加配置文件的可读性。
- option和list用来提高配置文件的可读性,并且在语法上也要求使用关键字来表示配置选项的开始。
引号的使用
- 通常不需要使用引号引上类型标识符(type)或值(value),引号只在封闭的值包含空格或制表符的情况下需要。它可以合法地使用双引号和单引号。
- 下面是合法的UCI文件选项语法示例:
- 下面的例子是错误的UCI文件语法:
演示案例
- 下面是OpenWrt中的一个实际配置文件(/etc/config/system)。
- “config system”语句:定义了一个配置节的开始,配置类型为“system”,但没有名称。
- 选项“option hostname OpenWrt”和“option timezone UTC”两行:定义了“config system”配置节的两个简单配置。
- “config timeserver ntp”语句:定义了另外一个配置节的开始,类型为“timeserver”,名称为“ntp”。
- 在开始带有list关键字的选项,表示有多个值被定义,所有的语句有同一个选项名称“server”。在这个的例子中均为NTP服务器地址,组合为相同顺序的单链表来 处理。
- OpenWrt有很多独立的第三方应用程序,大多数应用程序的软件包维护者已经制作了UCI兼容的配置文件,启动时由UCI配置文件转换为软件包的原始配置文件。这是在运行初始化脚本/etc/init.d/中执行的。
- 因此,当开始执行一 个UCI兼容的守护进程初始化脚本时,你应该意识到程序的原始配置文件被覆盖了。例如,在DNS代理服务器 dnsmasq进程启动的情况下,文件/var/etc/dnsmasq.conf 是从 UCI 配置文件/etc/config/dhcp生成并覆盖的,是运行/etc/init.d/dnsmasq脚本进行配置文件转换的。
- 配置文件的存储:因为应用程序的配置文件是启动时通过UCI转换生成的,因此它不需要存储在非易失性存储器中,通常存储在内存中而不是在闪存中,而var目录为其内容在正常运行时不断变化的目录,因此将var目录创建为/tmp目录的一个链接。
- OpenWrt的大多数配置都基于UCI文件,如果你想在软件原始的配置文件调整设置,可以通过禁用UCI方法来实现。
- UCI配置文件的修改:OpenWrt系统的核心配置分成很多个文件,并且都位于/etc/config目录下。每个文件涉及系统配置的某一部分。你可以用一个文本编辑器修改,或用命令行实用程序UCI编辑配置文件。UCI的配置文件也可通过各种编程 API(如 shell、Lua和C等)来修改,这也是 Web 接口例如LuCI修改UCI文件的方式。
- UCI配置文件修改后的重启:无论是通过一个文本编辑器还是命令行工具修改配置文件,在改变一个 UCI 的配置文 件后,受影响的服务或可执行程序必须由 init.d 进行重启,这样更新 UCI 配置才会真正生 效软件特定的配置文件。
- init.d对配置文件的转换:许多程序是通过它们的初始化脚本与UCI配置兼容的。init.d将UCI配置转换为它们。init.d首先在该软件预期的位置生成这样的一个配置文件,它通过 重新启动可执行程序再次读入配置。注意:如果只是直接启动可执行文件,没有通过 init.d 调用,将不会将一个 UCI 配置文件更新到特定程序相应的配置文件位置,在/etc/config/的 修改将不会对现有进程有任何影响。
- 所有的UCI配置文件均默认保存在“/etc/config”目录下:
演示案例
- 例如,在修改UCI配置文件时,如果你想将局域网网关IP地址从默认地址192.168.1.1修改为192.168.6.1,可以使用vi编辑器直接修改/etc/config/network。但是此处我们使用uci命令来修改。
- 下一步通过运行以下命令使修改生效。
- 在这种情况下,你需要使用新的IP地址来登录路由器设备。路由器常用功能配置文件。
- 在开发调整配置时,可以直接使用vi编辑器修改UCI配置文件。但是UCI统一配置文件的目的就是所有 OpenWrt 配置可以通过统一接口读取和修改。对于开发人员而言,如 果使用 awk 和 grep 工具来解析将是非常低效的,UCI实用工具提供了修改和分析UCI文件的脚本编程开发接口。
备注(重点)
- 当使用UCI工具写入配置文件时,配置文件都是整个重写并且不需要确认命令。这意味着在文件中任何多余的注释行和空行均会被删除。
- 如果你有 UCI 类型的配置文件,想保存自己的注释和空行,那就不应该使用UCI命令行工具来编辑文件。
- 命令格式:
- options如下:
- -c <path>:set the search path for config files (default: /etc/config)
- -d <str>:set the delimiter for list values in uci show
- -f <file>:use <file> as input instead of stdin
- -m:when importing, merge data into an existing package
- -n:name unnamed sections on export (default)
- -N:don't name unnamed sections
- -p <path>:add a search path for config change files
- -P <path>:add a search path for config change files and use as default
- -q:quiet mode (don't print error messages)
- -s:force strict mode (stop on parser errors, default)
- -S:disable strict mode
- -X:do not use extended syntax on 'show'
- command如下:
- 有些运行中的状态值没有保存在/etc/config目录下,而是保存在/var/state下,这时可 以使用“-P”参数来查询当前状态值。
- 网络配置的相关信息存放在/etc/config/network文件中。
- 下面我们修改“lan”这个网络接口的IP地址(修改完在下面图中可以看到“lan”这个网络接口的IP地址为我们设置的值)。
- 删除上面我们设置的IP地址。
- 概念:当有多个配置节类型相同或者为匿名配置节时,UCI使用数组数字引用它们。
- 规则如下:
- ①例如:OpenWrt 系统默认有 3 个网卡接口,可以通过network.@interface[0]来引用第一个,通过network.@ interface[1]来引用第二个,通过network.@interface[2]来引用第三个。
- ②也可以使用负索引, 例如network.@interface[−1],其中“−1”指的是最后一个,“−2”指的是倒数第二个,以此类推。
演示案例(获取各个网卡名称)
- 我这个OpenWrt系统中有两个网卡
- 当一个配置文件中的选项(option)为链表时,操作方法有所不同。
演示案例
- 例如我们的/etc/config/system配置文件中就有“list”形式的链表选项。
- 添加到链表中一个配置项:
- 删除链表中的一个配置项。
- 删除链表中的所有配置项。
- 下面我们创建一个helloRoute的配置。
- 第一步:先创建一个“hello”的配置文件
- 第二步:首先通过命令行创建配置文件。像上面的配置一样,如果你想增加一个配置节,大多数人都会想到使用“uci add”命令,但实际上“uci add”仅可以创建匿名配置节,不能完 成创建命名配置的目标,要使用“uci set”命令来完成。
- 第三步:设置配置节的3个选项。
- 查看配置文件内容。
- 脚本介绍:UCI模块提供了一个 shell 脚本(/lib/config/uci.sh)并封装了UCI命令行工具的功能, 这样方便了其他软件包在将UCI配置文件转换为自己格式的配置文件时使用。
- 主要的函数如下所示:需要这些函数需要导入/lib/config/uci.sh。
uci_load函数的注意事项
- 在单独导入uci.sh时,uci_load函数并不能执行成功,因为 uci_load函数引用了/lib/functions.sh的一些函数定义,因此在使用 uci_load 函数时需要先导入functions.sh的函数定义。
- 调用uci_load函数将配置设置到环境变量中时,uci_load函数又调用了 functions.sh 定义的 config()、option()、list()等函数。
- 脚本介绍:functions.sh的主要原理是将配置文件中的配置选项设置到环境变量中,然后提供接口函数在环境变量中获取。
- 调用uci_load函数将配置设置到环境变量中时,uci_load函数又调用了 functions.sh 定义的 config()、option()、list()等函数。
- 在使用这些函数时,以点开头来将这些函数加载到执行空间中,注意点和执行文件中间有 一个空格。例如:
- 主要的函数如下所示:
配置文件选项的写入与读取
- 我们知道functions.sh的主要原理是将配置文件中的配置选项设置到环境变量中,然后提供接口函数在环境变量中获取,下面我们以config_load与config_get函数为例,介绍一下执行过程。
- ①首先通过调用config_load函数将UCI配置读入当前环境变量中,默认从/etc/config目录下读取配置,并设置到环境变量中。
- ②然后使用config_get等函数进行读取和转换配置。
- ③我们以config_get函数为例来说明执行流程。config_get函数从环境变量中读取配置值并赋值给变量。该函数至少要3个参数。
- 第1个参数为存储返回值的变量。
- 第2个参数为所要读取的配置节的名称。
- 第3个参数是所有读取的选项名称。
- 第4个参数是为默认值,如果配置文件没有该选项则返回该默认值,是一个可选的参数。
- “uci_”开头的函数是/lib/config/uci.sh脚本提供的,“config_”开头得函数是/lib/functions.sh脚本提供的。
相同点
- 以“uci_”开头的函数和以“config_”开头的函数大多数功能完全相同。
不同点
- “uci_get”等函数直接从文件中获取,而“config_get”函数从环境变量中读取。
- 性能差异:“config_get”函数使用“config_load”一次从配置文件中读取设置到环境变量中,以后均不再进行磁盘操作。而“uci_get”每次均从文件中读取。
- 如果调用多次,两者性能差距就会显现,实际测试中两者相差10倍以上。因此在OpenWrt中大多使用以“config_”开头的“config_get”等函数进行配置文件转换。
- 下图所示为OpenWrt 12.09的一个实际代码,在启动时,从配置文件中获取主机名称,并设置到内核中。
- 上面我们介绍了UCI的脚本提供的命令接口,UCI还提供了C语言调用接口。下面在操作系统Ubuntu下来说明API的使用。
- 首先准备UCI编程接口的使用环境:UCI软件依赖Libubox,因此首先编译Libubox,Libubox库编译好之后,就可以再去编译UCI库了。
- 等到UCI库编译好之后,我们就可以在编写C语言程序时使用UCI库了。
- Libubox库介绍:Libubox是OpenWrt的一个必备的基础库,包含大小端转换、链表、MD5等实用工具基础库,采用Cmake来编译。
安装Cmake
- 。Cmake是跨平台的产生Makefile的命令行工具,它应用于在脚本文件中配置工程
- -D选项:设置工程选项。
- -i选项:打开交互提示来进行设置。
- CmakeLists.txt:Cmake是一个跨平台的编译系统生成工具。通过平台独立Cmake的listfiles文件来指定构建过程。这个文件在每一个源码目录树目录下均有一个,文件名为CmakeLists.txt。
- 安装Cmake命令如下:
编译、安装Libubox
- 第一步:下载Libubox的软件包。
- 第二步:使用cmake生成Makefile。
- 命令最后的一个点,代表当前路径。
- 设置了两个编译开关(BUILD_LUA:BOOL、BUILD_EXAMPLES:BOLL)为 OFF,这两个分别是lua和使用示例,我们不进行编译,因此把编译选项关闭。
- 第三步: 进行编译(make)、安装(make install)。
- 在进行编译时,编译过程中会输出编译进度百分比。
- 编译完成之后进行安装,安装到系统目录中,需要使用管理员权限并输入密码,因此会加上sudo命令。
- 安装内容包含头文件和动态链接库文件。头文件默认安装在/usr/local/include/libubox目录下,动态链接库libubox.so和 libubox.a安装在/usr/local/lib/目录下。
- Libubox安装完成后就可以编译安装UCI软件了。
编译、安装UCI库
- 第一步:下载UCI软件包。
- 第二步:使用cmake生成Makefile。
- 第三步:编译、安装UCI。
- UCI库的头文件安装在/usr/local/include目录下,动态链接库安装在/usr/local/lib/ libuci.so,可执行程序为/usr/local/bin/uci。
- 第四步:因为系统还不知道动态链接库已经安装,运行该命令会告诉系统重新加载动态链接库,这样UCI动态链接库就可以使用了。
- UCI库编译好之后,就可以在C语言程序中使用UCI库了(-luci),例如下面使用gcc编译一个带有与UCI库的C程序。
- UCI接口命名非常规范,统一以小写的uci开头并放在uci.h头文件中。
- 大多数函数的第一个参数均为uci_context的指针变量。这个变量在程序初始化时调用uci_alloc_context函数分配空间并设置初始值。在程序执行结束时调用uci_free_context函数释放空间。
- UCI接口有设置函数uci_set,但没有相应的获取函数uci_get,UCI使用uci_lookup_ptr来提供查询功能,如果查到则通过获取ptr变量的值来获取配置的值。
- UCI API的使用案例,见文章:https://blog.csdn.net/qq_41453285/article/details/102545618。
- 我是小董,V公众点击"笔记白嫖"解锁更多OpenWrt资料内容。
以上就是本篇文章【一文打尽UCI统一配置接口、UCI配置文件、UCI工具用法、UCI配置脚本、UCI API编程接口(Libubox库、UCI库)】的全部内容了,欢迎阅览 ! 文章地址:http://ww.kub2b.com/tnews/266.html
栏目首页
相关文章
动态
同类文章
热门文章
网站地图
返回首页 企库往资讯移动站 http://ww.kub2b.com/mobile/ , 查看更多