二、Luci中的UCI API的使用

本文详细介绍了OpenWrt中UCI(Unified Configuration Interface)的配置管理和命令行用法,包括如何修改配置文件、UCI文件的语法以及UCI命令的示例。此外,还讲解了在LUA中使用UCI API的方法,如获取、设置、删除配置选项,以及处理列表类型的数据。这些内容对于理解和操作OpenWrt系统的配置至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、UCI

openwrt中的各个应用程序和服务,都拥有自己的配置文件,但是每个应用程序的配置文件所在目录,都不是一定是一致的。所以为了能够更加方便的修改配置和解决配置不兼容过的问题。 openwrt对一些应用程序进行了UCI配置的支持,即想要修改应用程序配置,只需要修改UCI配置即可。而应用程序的启动脚本,会对UCI配置进行读取,而生成实际的应用程序配置。

比如说samba ,其真正的原配置文件位于 etc/samba/smb.conf ,对应的UCI文件位于 etc/config/samba 让他们之间产生关联的文件,位于etc/inint.d/samba。原配置文件根据他自己对于**/etc/config** 下面的UCI配置文件选项,去设置自己应用程序的配置。当修改UCI文件之后,相应的服务或者应用程序不会自动更新为最新状态,还需要运行 /etc/init.d/samba start。UCI文件中的配置才会更新到应用程序实际配置中去。
1.1、UCI文件语法

package 'example' 

config 'example' 'test'
        option   'string'      'some value'
        option   'boolean'     '1'
        list     'collection'  'first item'
        list     'collection'  'second item'

config ‘example’ ‘test’ :表示一个段的开始,其中example是段的类型,test为段的名字。
段也可以没有名字,像config ‘example’,但是必须要有类型,类型指示了uci程序怎么去处理后面的option内容。

option ‘string’ 'some value’和 option ‘boolean’ ‘1’ :两个语句定义了段内的两个标识符的值,虽然它们一个是string一个是boolean,但是在语法没有任何区别。

  • boolean后面可以跟’0’, ‘no’, ‘off’, ‘false’ 中的一个作为否的值,或者’1’, ‘yes’, ‘on’,
    ‘true’ 作为逻辑是的值。
  • 后面两行以list开头的语句,是为某个有多种选项值的option所定义的,在同一option中的选项值,它们应该有同样的名字,在这里的名字为collection。最终这两个值会收纳到同一个list表中,表中出现的顺序即你这里所定义的;
  • 标识符option和list是为了更易读而加上的,在语法上不是必须的;但是建议加上。UCI标识符和配置文件名称所包含的字符必须是由a-z,
    0-9和_组成。 选项值则可以包含任意字符,只要这个值是加了引号的。

2、UCI命令行的用法

Usage: uci [<options>] <command> [<arguments>]

Commands:
        batch
        export     [<config>]
        import     [<config>]
        changes    [<config>]
        commit     [<config>]
        add        <config> <section-type>
        add_list   <config>.<section>.<option>=<string>
        del_list   <config>.<section>.<option>=<string>
        show       [<config>[.<section>[.<option>]]]
        get        <config>.<section>[.<option>]
        set        <config>.<section>[.<option>]=<value>
        delete     <config>[.<section>[[.<option>][=<id>]]]
        rename     <config>.<section>[.<option>]=<name>
        revert     <config>[.<section>[.<option>]]
        reorder    <config>.<section>=<position>

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'

2.1、UCI命令使用示例

#把uhttpd的监听端口从80换成8080
root@OpenWrt:~# uci set uhttpd.main.listen_http=8080 
root@OpenWrt:~# uci commit uhttpd 
root@OpenWrt:~# /etc/init.d/uhttpd restart 
root@OpenWrt:~#

#导出整体配置信息
root@OpenWrt:~# uci export httpd 
package 'httpd' 
config 'httpd' 
    option 'port' '80' 
    option 'home' '/www' 
root@OpenWrt:~#

#显示一个给定配置的树
root@OpenWrt:~# uci show httpd 
httpd.@httpd[0]=httpd 
httpd.@httpd[0].port=80 
httpd.@httpd[0].home=/www 
root@OpenWrt:~#

#显示一个option的值
root@OpenWrt:~# uci get httpd.@httpd[0].port 
80 
root@OpenWrt:~#

#追加list的一个条目
uci add_list system.ntp.server='0.de.pool.ntp.org'

#替换一个list
uci delete system.ntp.server 
uci add_list system.ntp.server='0.de.pool.ntp.org' 
uci add_list system.ntp.server='1.de.pool.ntp.org' 
uci add_list system.ntp.server='2.de.pool.ntp.org'

/**
*UCI路径
*假设有下面的UCI文件
*/etc/config/foo 
**/

config bar 'first' 
    option name 'Mr. First' 
config bar 
    option name 'Mr. Second' 
config bar 'third' 
    option name 'Mr. Third'
那么下面三组路径的执行得到的值分别各自相等

# Mr. First 
uci get foo.@bar[0].name 
uci get foo.@bar[-0].name 
uci get foo.@bar[-3].name 
uci get foo.first.name 
# Mr. Second 
uci get foo.@bar[1].name 
uci get foo.@bar[-2].name 
# uci get foo.second.name 本条语句不工作,因为second没有定义 
# Mr. Third 
uci get foo.@bar[2].name 
uci get foo.@bar[-1].name 
uci get foo.third.name
如果show,则会得到这样的值

# uci show foo 
foo.first=bar 
foo.first.name=Mr. First 
foo.@bar[0]=bar 
foo.@bar[0].name=Mr. Second 
foo.third=bar 
foo.third.name=Mr. Third
执行uci show foo.@bar[0]得到

# uci show foo.@bar[0] 
foo.first=bar 
foo.first.name=Mr. First
查询输出
root@OpenWrt:~# uci -P/var/state show network.wan
uci: Entry not found
network.loopback=interface
network.loopback.ifname=lo
network.loopback.proto=static
network.loopback.ipaddr=127.0.0.1
network.loopback.netmask=255.0.0.0
network.loopback.up=1
network.loopback.connect_time=10749
network.loopback.device=lo
network.lan=interface
network.lan.type=bridge
network.lan.proto=static
network.lan.netmask=255.255.255.0
network.lan.ipaddr=10.0.11.233
network.lan.gateway=10.0.11.254
network.lan.dns=8.8.8.8
network.lan.up=1
network.lan.connect_time=10747
network.lan.device=eth0
network.lan.ifname=br-lan

注意:在修改UCI配置之后,比如使用set命令修改某个ip地址之后,再使用get命令来进行查看可以看到修改成功了,但是实际上配置文件中还是未修改之前的值。是因为uci修改之后的值是临时性的,临时值保存在/tmp/.uci/ 目录下面。比如修改了network配置和wireless配置,.uci/目录下会有一个network文件和wireless文件,里面存储的是每一次的改动信息。如果想要让改动的值真正的写入etc/config/下面的配置文件中,需要调用uci commit 命令,此命令会提交所有的更改,也可以使用 uci commit network 。只提交network的更改。

3、在LUA中使用UCI API

除了uci为lua语言提供的部分api外,在luci中也封装了一些api,源码位于luci/model/uci.lua中。
导入后需要初始化

1. 不带参数初始化(配置目录默认/etc/config)

local uci = require “luci.model.uci”.cursor()

2. 包含状态值

x = uci.cursor(nil, “/var/state”)

3. 指定配置目录

x = uci.cursor("/etc/mypackage/config", “/tmp/mypackage/.uci”)

4.API使用实例

以下示例配置文件为 /etc/config/test

1、x:get(“config”, “sectionname”, “option”)

返回对应config下某个sectionname的option值

在这里插入图片描述

uci:get("test","loopback","proto") --> 'static'
2、x:set(“config”, “sectionname”, “option”, “value”)

设置对应config下某个sectionname对应的option值
在这里插入图片描述

uci:set("test","ens38","proto","dhcp")  -> true
uci:commit("test")
uci:get("test","ens38","proto") -> "dhcp"

设置列表变量的值

uci:set("test","ens38","ipaddr",{"127.0.0.1","127.0.0.2"})->true
uci:commit("test")
uci:get("test","ens38","ipaddr")->{"127.0.0.1","127.0.0.2"}

在这里插入图片描述

3、x:set(“config”,“name”,“type”)

添加一个类型为type,名称为name的section段

uci:set("test","ens33","interface") -true
uci:commit("test")
--新添加的一个 config interface 'ens33'
4、x:add(“config”, “type”)

添加一个匿名的section段

uci:add("test","test_type") -> cfg0434e6
uci:commit("test")
--添加匿名段时,uci会自动生成一个name
添加的匿名段为 config test_type
5、x:delete(“config”, “sectionname”)
删除name为sectionname的段
uci:delete("test","ens33") ->true
uci:commit("test")
--删除掉了name为ens33的段,name在同一个配置文件中
--是唯一的,所以通过name可以直接定位到某个具体的段
--如果需要删除匿名的段,建议使用foreach方法对type进行
--遍历。找到要删除的段进行删除。
6、x:delete(“config”, “sectionname”, “option”)

删除name为sectionname的段的某个选项option

uci:delete("test","ens38",'ipaddr')
uci:commit("test")
uci:get("test","ens38","ipaddr") --uci: Entry not found

在这里插入图片描述

7、x:foreach(“config”, “type”, function(s) … end)

对某个type的段进行遍历,第三个参数为回调函数,函数接收的变量为某个段
比如有配置信息如下所示,type均为interface,其中包含一个匿名段。
在这里插入图片描述

uci:foreach("test","interface",function (s)
   log.print_r(s)
end)

打印数据如下所示:.name为其sectionname,如果是匿名段,则会分配一个名字。比如要删除匿名段时,可以根据此名称调用delete(“config”, “sectionname”)
在这里插入图片描述

8、x:delete_all(config,type,comparator)

该函数内部使用foreach方法对config某个type类型进行遍历,同时把该section段传入comparator函数中。如果comparator函数返回true则删除该section段,反之不删除。如果不传递comparator 参数。则全部进行删除。

--下面的代码表示删除 type为'interface',name为 'ens38' 的section段 
x:delete_all('test','interface',function(section) 
    if section[".name"] == 'ens38' then
    	return true
    end
    return false
end)
9、x:section(config, type, sectionname, values)

直接创建一个类型为type,名称为sectionname,选项值为values 的section段

uci:section('test','interface','ens33',{
   hello = 'world',
   --如果需要初始化list的值,需要传递table
   ipaddr = {'127.0.0.1','127.0.0.2'}
}) -> ens33 创建成功返回name,失败返回false
uci:commit("test")

在这里插入图片描述

10、x:tset( config, sectionname, values)

设置名称为sectionname的section段的值

uci:tset('test','ens33',{
   hello = 'world_change',
   --如果需要设置列表值,可以传入table
   hoby = {'run','sing'}
}) --true

在这里插入图片描述

11、x:get_bool(“config”, “sectionname”, “option”)

与get方法类似,不过是获取的是Boolean类型的值,如果该选项的值为字符串的 ‘1’、‘true’、‘yes’、‘on’ ,则返回true。其他值返回false

12、x:get_list(“config”, “sectionname”, “option”)

与get方法类似,不过获取的是list类型的值,如果不是list则会转成list

在这里插入图片描述

uci:get_list('test','ens33','hello') -> {'world_change'}
uci:get_list('test','ens33','hoby') ->{'run','sing'}
13、 x:get_first(‘config’,“type”,“option”,‘default’)

从给定的配置文件的指定类型的section段中加载第一个出现的option选项。如果不给定option选项,则返回第一个指定类型的sectionname,如果不存在此选项,则返回default默认值,如果不传入默认值,返回nil

在这里插入图片描述

--不传入option时,返回第一个interface类型的名称
uci:get_first('test','interface')->loopback
--返回类型为interface的第一个ifname选项
uci:get_first('test','interface','ifname') ->lo
--返回类型为interface的第一个hello选项
uci:get_first('test','interface','hello')->world_change
--该选项有值,则返回该选项的值
uci:get_first('test','interface','ifname',true) ->lo
--该选项没有值,则返回传递的默认值
uci:get_first('test','interface','ifname1',true) ->true
14、x:set_list(‘config’,‘sectionname’,‘option’,‘value’)

设置一个选项的值为列表类型,value可以是字符串,也可以是list,如果是字符串,将自动转成list,如果value为空,或者为空列表,则会删除该option

在这里插入图片描述

--不传递value或者value长度为0时,内部会调用delete删除该option
x:set_list('test','ens33','hoby') ->true
x:set_list('test','ens33','hoby',{}) -> true

在这里插入图片描述

--传递字符串时会自动处理成list
x:set_list('test','ens33','hoby','swimming') ->true

在这里插入图片描述

15、x:get_confdir()

返回配置文件目录:/etc/config

16、x:getsave_dir()

返回未保存的更改所存储的目录: /emp/.uci

17、x:revert(“config”)

取消某个config文件的更改,config为配置文件名称,如果不传递,则取消所有更改。

18、x:commit(“config”)

提交某个config文件的更改,将更改写进etc/config/下的某个文件中,如果不传递则提交全部更改。

<think>我们正在讨论的是OpenWrt系统中的UCI配置读取问题。用户希望在代码中读取UCI配置值。根据引用[1][2],我们知道UCI配置文件存储在/etc/config/目录下,并且有特定的格式。在C语言程序中,我们可以使用OpenWrt提供的libuci库来读取这些配置。 步骤: 1. 包含必要的头文件:<uci.h> 2. 初始化UCI上下文:struct uci_context *ctx = uci_alloc_context(); 3. 加载配置文件:struct uci_package *p = uci_load(ctx, "配置文件名", &err); 4. 遍历配置节(section)选项(option)来获取值。 5. 使用完毕后释放资源。 注意:使用libuci库需要在编译时链接libuci,即在Makefile中添加-luci。 下面是一个示例代码,展示如何读取系统配置(system)中的主机名(hostname):</think>### 在代码中读取UCI配置值的方法 在OpenWrt开发中,通过C语言程序读取UCI配置需要以下步骤: #### 1. **包含头文件** ```c #include <uci.h> // UCI核心库头文件[^1] ``` #### 2. **初始化UCI上下文** ```c struct uci_context *ctx = uci_alloc_context(); // 创建UCI上下文 if (!ctx) { // 错误处理 perror("Failed to allocate UCI context"); return -1; } ``` #### 3. **加载配置文件** ```c struct uci_package *pkg; const char *config_name = "system"; // 例如系统配置文件 if (uci_load(ctx, config_name, &pkg) != UCI_OK) { // 错误处理 uci_free_context(ctx); return -1; } ``` #### 4. **获取配置值** ```c const char *value = NULL; struct uci_section *section = uci_lookup_section(ctx, pkg, "cfg02f02f"); // 引用[1]中的配置节名 if (section) { // 获取hostname值 value = uci_lookup_option_string(ctx, section, "hostname"); if (value) { printf("Hostname: %s\n", value); // 输出: Hostname: OpenWrt } // 获取timezone值 value = uci_lookup_option_string(ctx, section, "timezone"); if (value) { printf("Timezone: %s\n", value); // 输出: Timezone: UTC } } ``` #### 5. **完整示例(读取无线配置)** ```c #include <stdio.h> #include <uci.h> int main() { struct uci_context *ctx = uci_alloc_context(); struct uci_package *pkg; // 加载无线配置文件[^2] if (uci_load(ctx, "wireless", &pkg) != UCI_OK) { fprintf(stderr, "Failed to load wireless config\n"); return 1; } // 遍历所有无线配置节 struct uci_element *e; uci_foreach_element(&pkg->sections, e) { struct uci_section *s = uci_to_section(e); printf("Section: %s\n", s->type); // 读取MAC地址配置 const char *mac = uci_lookup_option_string(ctx, s, "macaddr"); if (mac) printf("MAC Address: %s\n", mac); } // 清理资源 uci_unload(ctx, pkg); uci_free_context(ctx); return 0; } ``` #### 6. **编译注意事项** 在Makefile中添加UCI库链接: ```makefile LIBS += -luci # 链接UCI库 ``` #### 7. **关键API说明 | 函数 | 作用 | |------|------| | `uci_alloc_context()` | 创建UCI上下文 | | `uci_load()` | 加载配置文件 | | `uci_lookup_section()` | 查找配置节 | | `uci_lookup_option_string()` | 获取字符串类型配置值 | | `uci_unload()` | 卸载配置包 | | `uci_free_context()` | 释放上下文资源 | > **注意**:UCI配置值修改后需调用`uci commit`才会持久化到文件系统[^1]。程序读取的是当前内存中的配置状态。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值