OpenWrt 系统UCI详解(Lua、C语言调用uci接口实例)

news/2025/1/7 9:28:49/文章来源:https://www.cnblogs.com/cheyunhua/p/18653292

1 UCI简介

“uci"是"Unified Configuration Interface”(统一配置界面)的缩写,用于OpenWrt整个系统的配置集中化。

很多后台服务有自己的配置文件,并且配置文件格式都不相同,OpenWrt系统中需要开启各种服务,为了解决配置不兼容的问题,统一采用uci格式的配置文件。

img

当然统一的前提是需要各个模块做好适配,所以要想把某个服务集成到OpenWrt系统中,需要增加一个转换层,用于uci配置到服务配置的转换,通常这个工作放在init脚本中处理。

img

以samba服务器为例,

在一般的linux系统中,启动samba服务直接修改/etc/samba/smb.conf重启服务即可,但在openwrt中,不直接修改/etc/samba/smb.conf,而是修改/etc/config/samba配置文件,然后执行/etc/init.d/samba restart

img

以下为init脚本的部分代码,这段代码中就包含了uci配置到samba配置的转换工作。

img

2 uci配置格式

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

config ‘example’ ‘test’ 语句表示一个section的开始,这里的配置类型是example,配置名是test。配置中也允许出现匿名节,即自定义了配置类型,而没有配置名的节。配置类型对应配置处理程序来说是十分重要的,因为配置程序需要根据这些信息来处理这些配置项。

option ‘string’ ‘some value’ 和 option ‘boolean’ ‘1’ 定义了一些简单值。文本选项和布尔选项在语法上没有什么差异。布尔选项中可以用'0' , ‘no’, ‘off’, 或者’false’来表示false值,或者也可以用'1', ‘yes’,‘on’或者’true’来表示真值。

以list关键字开头的多个行,可用于定义包含多个值的选项。所有共享一个名称的list语句,会组装形成一个值列表,列表中每个值出现的顺序,和它在配置文件中的顺序相同。如上例中,列表的名称是’collection’,它包含了两个值,即’first item’和’second item'。

‘option’和’list’语句的缩进可以增加配置文件的可读性,但是在语法不是必须的。

通常不需要为标识符和值加引号,只有当值包括空格或者制表符的时候,才必须加引号。同时,在使用引号的时候,可以用双引号代替单引号。

下面列举的例子都是符合uci语法的正确配置:

  • option example value
  • option ‘example’ value
  • option example “value”
  • option “example” ‘value’
  • option ‘example’ “value”

反之,以下配置则存在语法错误

  • option ‘example" “value’ (引号不匹配)
  • option example some value with space (值中包含空格,需要为值加引号)

还有一点是必须知道的,即UCI标识符和配置文件名称所包含的字符必须是由a-z, 0-9和_组成。 选项值则可以包含任意字符,只要这个值是加了引号的。

3 uci命令的用法

img

uci配置文件支持通过uci shell命令进行操作,支持set、get、show、export等基本操作。当然最常用的就是set和get命令。

在进行uci命令操作之前,我们先查看/etc/config/有哪些配置文件,这样我们可以知道操作哪个配置文件(当然也可以直接uci show,可以看到所有的配置信息,但数据较多,还是习惯先看看config目录有哪些配置)

img

现在可以针对某个配置进行操作,比如network配置,先通过cat查看配置文件中的内容,看看数据格式

img

然后通过 uci show network命令查看具体的uci配置选项,用于查看具体的uci变量名称

img

比如我们获取单个option变量值,获取lan口ip地址

可以通过uci get network.lan.ipaddr 命令获取

img

也可以通过set命令修改某个变量的值

如设置lan口ip地址为192.168.188.1

uci set network.lan.ipaddr=192.168.188.1

img

可以看到已经成功修改了lan ip的值,但值得注意的是,通过cat /etc/config/network并不能查看到最新设置的值,这是因为通过uci set命令只修改了变量的临时值,并没有保存到配置文件中。这个临时值保存在/tmp/.uci/目录中。

img

临时目录中的文件内容只显示修改的变量,如果多次修改会显示多个内容,会显示所有的历史记录。现在我们看看多次修改后临时目录文件中的内容

img

为了让修改的值在/etc/config目录中生效,我们还需要执行uci commit命令,该命令类似于svn commit,会把修改的记录提交。

uci commit会将所有改变提交,我们也可以只提交某个配置文件的修改,如uci commit network,这样只会提交network的修改内容。

4 常用的uci配置和命令

4.1 重要配置文件

配置文件说明
/etc/config/system 系统配置,如主机名、时区等
/etc/config/network 网络配置,lan口ip、wan口ip、vlan等
/etc/config/dhcp Dhcp服务器配置
/etc/config/firewall 防火墙配置
/etc/config/uhttpd Web服务器配置(默认)
/etc/config/dropbear Ssh服务器配置
/etc/config/luci Luci框架配置
   

4.2 常用配置命令

  • 网络配置
命令说明
uci show network 查看所有网络配置
uci get network.lan.ipaddr 获取lan口ip地址
uci set network.lan.ipaddr=192.168.2.1 修改lan口ip地址为192.168.2.1
uci get network.wan.proto 查看wan口ip地址获取方式(dhcp、static、pppoe)
uci set network.wan.proto=static 配置wan口ip地址获取方式为静态
uci get network.wan.ipaddr 获取wan口ip
uci set network.wan.ipaddr=192.168.100.100 配置wan口ip为192.168.100.100
uci get network.wan.netmask 获取wan口子网掩码
uci set network.wan.netmask=255.255.255.0 配置wan口子网掩码为255.255.255.0
uci get network.wan.gateway 获取默认网关地址
uci set network.wan.gateway=192.168.100.1 配置默认网关地址为192.168.100.1
uci get network.lan.ifname 获取lan口接口名(eth0)
uci get network.wan.ifname 获取wan口接口名(eth1)
uci show network.wan 查看所有wan配置
uci show network.lan 查看所有lan配置
uci commit network 保存网络配置
uci revert network 放弃修改的网络配置(在commit之前可以revert)
  • 其他配置
命令说明
uci show system 查看所有系统配置
uci get system.@system[0].hostname 获取系统主机名
uci get system.@system[0].timezone 获取当前系统时区(CST-8)
uci get system.ntp.enabled 获取ntp开关
uci get luci.ccache.enable 查看luci是否启用缓存
uci get luci.languages.zh_cn 获取luci当前使用的语言
uci get uhttpd.main.home 获取web服务器根目录
uci get uhttpd.main.listen_http 获取web服务器监听ip和端口
uci get uhttpd.main.redirect_https 查看web服务器是否强制https
uci get firewall.@zone[1].masq 查看是否开启地址伪装(snat)
uci get dropbear.@dropbear[0].PasswordAuth 查看ssh是否开启密码认证
uci get dropbear.@dropbear[0].Port 查看ssh监听端口号
uci get dropbear.@dropbear[0].Interface 查看ssh监听的网卡接口
uci show 查看所有uci配置
   

5 c语言中使用uci

5.1 引用说明

头文件 <uci.h>

引用库: +libuci

5.2 常用结构体

结构体说明相关接口
struct uci_context Uci上下文,用于存储配置路径、配置package等,使用uci前必须分配一个ctx uci_loaduci_unloaduci_alloc_contextuci_free_context
struct uci_package 对应一个配置包,如network、wireless uci_lookup_packageuci_loaduci_unload
struct uci_section 对应配置的一个节(section) uci_lookup_section
struct uci_option 对应某个配置项 uci_lookup_option_stringuci_lookup_option
     

5.3 常用接口

常用接口说明
int uci_set(struct uci_context *ctx, struct uci_ptr *ptr) 设置uci值
int uci_del_list(struct uci_context *ctx, struct uci_ptr *ptr) 删除list option
int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr) 增加list option
int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr) 删除节点(option)
int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended) 查询元素指针
int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr) 重命名节(option)
int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res) 添加一个节
struct uci_context *uci_alloc_context(void) 分配上下文空间
void uci_free_context(struct uci_context *ctx) 释放上下文空间
int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package) 加载配置到内存
int uci_set_confdir(struct uci_context *ctx, const char *dir) 设置配置目录
int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overwrite) 提交修改的值
struct uci_option *uci_lookup_option(struct uci_context *ctx, struct uci_section *s, const char *name) 查询option指针
const char *uci_lookup_option_string(struct uci_context *ctx, struct uci_section *s, const char *name) 获取一个option string值
struct uci_section *uci_lookup_section(struct uci_context *ctx, struct uci_package *p, const char *name) 查询package中的section
struct uci_package *uci_lookup_package(struct uci_context *ctx, const char *name) 在上下文中获取package指针
   

5.4 C语言操作uci配置实例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <uci.h>static struct uci_context *uci_ctx = NULL;
static struct uci_package *uci_test;
static struct uci_package *
config_init_package(const char *config)
{struct uci_context *ctx = uci_ctx;struct uci_package *p = NULL;if (!ctx){ctx = uci_alloc_context();uci_ctx = ctx;ctx->flags &= ~UCI_FLAG_STRICT;//if (config_path)//  uci_set_confdir(ctx, config_path);}else{p = uci_lookup_package(ctx, config);if (p)uci_unload(ctx, p);}if (uci_load(ctx, config, &p))return NULL;return p;
}
int config_alloc(void)
{uci_test = config_init_package("test");if (!uci_test){printf("Failed to load test config\n");return -1;}return 0;
}int config_free(void)
{if (uci_test){uci_unload(uci_ctx, uci_test);uci_test = NULL;}if (uci_ctx){uci_free_context(uci_ctx);uci_ctx = NULL;}
}int main(int argc, char *argv[])
{int ret = 0;int enable = 0;config_alloc();struct uci_section *global_sec = uci_lookup_section(uci_ctx, uci_test, "global");if (!global_sec){printf("get global section failed\n");config_free();return 0;}char *name = uci_lookup_option_string(uci_ctx, global_sec, "name");if (!name){printf("name option not found.\n");config_free();return 0;}printf("name = %s\n", name);free(name);struct uci_ptr ptr ={.package = "test",.section = "global",.option = "name",.value = "xxxxxxxxxx"};ret = uci_set(uci_ctx, &ptr);   if(ret != UCI_OK){printf("set name...failed\n");}else{printf("set name...ok\n");}uci_save(uci_ctx, ptr.p);uci_commit(uci_ctx, &ptr.p, false);config_free();return 0;
}

5.5 Lua中使用uci

5.5.1 配置文件实例

/etc/config/test

config global 'global'option name 'derry'option id '1'list address 'shenzhen'list address 'guangzhou'list address 'beijing'

5.5.2 cursor初始化的几种方式

1. 不带参数初始化(配置目录默认/etc/config)x = uci.cursor()2. 包含状态值x = uci.cursor(nil, "/var/state")3. 指定配置目录x = uci.cursor("/etc/mypackage/config", "/tmp/mypackage/.uci")

5.5.3 Lua常用的uci接口

lua接口说明
x:get(“config”, “sectionname”, “option”) 返回字符串 或 nil(没找到数据时)
x:set(“config”, “sectionname”, “option”, “value”) 设置简单的字符串变量
x:set(“config”, “sectionname”, “option”, { “foo”, “bar” }) 设置列表变量
x:delete(“config”, “section”, “option”) 删除选项
x:delete(“config”, “section”) 删除段
x:add(“config”, “type”) 添加一个匿名section(段)
x:set(“config”, “name”, “type”) 添加一个类型为 “type”的section(段),名称为”name”
x:foreach(“config”, “type”, function(s) … end) 遍历所有类型为的"type"段,并以每个"s"为参数调用回调函数. s 是一个包含所有选型和两个特有属性的列表s['.type’] → 段类型s['.name'] → 段名称如果回调函数返回 false [NB: not nil!], foreach() 在这个点会终止,不再继续遍历任何剩余的段. 如果至少存在一个段且回调函数没有产生错误,foreach() 会返回 true; 否则返回false.
x:revert(“config”) 取消修改的值
x:commit(“config”) 保存修改的值到配置目录文件,默认目录/etc/config

6 Lua操作uci配置实例1

#!/usr/bin/lua
require("uci")
x = uci.cursor()
function show_test_config()name = x:get("test", "global", "name")id = x:get("test", "global", "id")addr_list = x:get("test", "global", "address")print("name="..name)print("id="..id)
for key, value in ipairs(addr_list) 
do 
print("address["..key.."]----"..value) 
end
endprint("==========before change=========")
show_test_config()
x:set("test", "global", "name", "xxxxxxx")
x:set("test", "global", "id", "8888888")x:set("test","global","address",{"1111","2222","33333","4444","5555"})
x:commit("test")
print("==========after change=========")
show_test_config()

运行结果:

img

6.0.4 Lua操作uci配置实例2

x=uci.cursor()

conf=x:get_all(“test”, “global”)

#!/usr/bin/lua
require("uci")
x=uci.cursor()
conf=x:get_all("test", "global")print(conf["name"]);
print(conf["id"]);
for key, value in ipairs(conf["address"])
doprint(value);
end

运行结果:

img

以上内容转载自本链接,若有侵权请联系站长

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/864388.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

macbook 双系统win7忘密码 解决办法 通用

1开机出现以下图片按开机键强制重启2选择这一个3跟着选择4等待时间较长5继续678点击计算机9选择c盘10选择Windows进入system32文件夹11右键修改名字 将sethc 修改为sethc112然后键盘上输入cmd13将cmd名字修改为sethc 14关掉所有点击完成 15然后开机来到登录界面 按5次shift 次数…

GoLang 2024 安装激活详细使用教程(激活至2026,实测是永久,亲测!)

开发工具推荐:GoLang 安装激活详细使用教程(激活至2026,实际上永久,亲测!)申明:本教程 GoLang 补丁、激活码均收集于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除。若条件允许,希望大家购买正版 ! GoLang是JetBrains公司推出的一款功能强大的GO语言集成…

数值计算方法(3) 数值微分方法

+++ date = 2024-12-21T15:45:47+08:00 draft = true title = 数值计算方法(3) 数值微分方法 +++ 初次发布于我的个人文档 上一期讲了数值积分方法,这一次自然是要讲数值微分方法的,不然太不完善了。 更何况数值微分方法其实是基于数值积分方法得到的。 我们先从比较简单的估…

.Net NativeAOT另外一种选择-bflat

https://www.qiufengblog.com/articles/dotnet-native-bflat.html前言 说起bflat,还得先说NativeAOT,在.Net 7时,正式把NativeAOT合到Runtime中,地位是明显上升了,对NativeAOT的代码提交也越来越多了,之前还是corert时,几年也没有太大的进展. 这个时候的成果还是有ILC(ILCompil…

20241415 《计算机基础与程序设计》课程总结

20241415 《计算机基础与程序设计》课程总结 每周作业链接汇总 第一周作业 参考基于VirtualBox虚拟机安装Ubuntu图文教程安装Linux系统 自学计算机科学概论》并提出问题第二周作业 了解计算思维和计算机结构第三周作业 计算机的数据表示法 C语言的基本数据类型第四周作业 门电路…

centos7 开启网卡相关设置

默认网卡是ens33 查看ip命令 ip a 或 ip addr 对于没有启用的网卡,使用命令ifup,开启网卡。注意网卡的名称ens33 找到自己对应的ifup ens33 永久默认启用网卡,关机或重启后,网卡自动启用该配置文件在/etc/sysconfig/network-scripts文件夹下,可以提前备份下 ifcfg-ens3…

20241417 《计算机基础与程序设计》课程总结

20241417 《计算机基础与程序设计》课程总结 每周作业链接汇总 第一周作业:链接 简要内容:课程概论,工业革命与浪潮之巅,信息与信息安全,计算机系统概论,计算机安全,计算的限制,计算思维第三周作业:链接 简要内容:数字分类与计数法,位置计数法,进制转换,模拟数据与…

PCIe扫盲——Base Limit寄存器详解

上一篇文章介绍了Type0型配置空间Header中的BAR的作用和用法,但是PCIe中的桥设备(Switch和Root中的P2P)又是如何判断某一请求(Request)是否属于自己或者自己的分支下的设备的呢?(定义范围) 这实际上是通过Type1型配置空间Header中的Base和Limit寄存器来实现的,这篇文章…

用.NET X64 Native AOT编写的操作系统

https://blog.csdn.net/sd7o95o/article/details/1331911601.前言很多人想学习下.Net前沿技术和核心技术,这里推荐一个适合大家学习的案例,用.NET X64 Native AOT编写一个操作系统。 2.概述MOOS(To Make My Own Operating System Project)是一个采用.NET x64 Native AOT技术…

Win32汇编学习笔记05

定位关键点3种方法: 过程函数 api 字符串 但是不确定用要哪一种方法,可以3种方法都用一下,因为在不同的程序,实用的方法是不一样的 窗口程序看控件信息 1.通过OD去看还可以用 spy ++ 查看还可以用vs2019 ,打开软件,找到对应控件直接看属性一般拿句柄没用,因为按钮是响应 WM_COM…

2025年,勇敢探索,才能突破困境

新年第一篇文章,不聊技术,聊聊今年的计划,以及未来的发展趋势。 在24年的第一篇文章中,我用“苟住求活”这个词形容了我当时的判断,如今回过头再看2024年,大家都过的很挣扎。经济环境进一步恶化,就业机会越发的稀少,降本增效降薪裁员,是去年很多人的真实经历。 今年的…

Java集合 —— LinkedList详解(源码)

在学习LinkedList之前先来了解一下链表链表 概念链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序通过链表中的指针链接次序实现的图中的1、2、3、4、5都是结构体,称为结点;结构体包含所存的数据和下一结点的地址。顺序表中的地址是连续的,而链表中的…