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/下的某个文件中,如果不传递则提交全部更改。