OpenWrt系统配置UCI

UCI简介

UCI (Unified Configuration Interface) 是 Openwrt 中的统一配置接口。官方文档参考
每一个程序的配置文件都保存在/etc/config 目录,可以通过文本编辑器、uci(一个可执行程序)以及各种 API(Shell、Lua 和C)来修改这些配置文件。

UCI 文件格式

UCI 配置文件由一个或多个 config 语句组成,每一个 config 语句伴随着一个或多个 option 语句。这样的由一个 config 语句以及伴随的几个 option 语句组成的段落就叫做一个 section。

例如:在/etc/config 目录下创建一个配置文件 example,其内容如下
root@OpenWrt:~# vi /etc/config/example

config example 'test'
		option name 'value'
		list collection 'first item'
		list collection 'second item'
  • config example ‘test’ 中的 example 表示这个 section 的 type ,'test’表示这个 section 的name,为空时称为匿名section 。name 方便后续直接使用,如果是匿名则需要用 @type[0] @type[1]代表文件中先后的通type的section,@type[-1] @type[-2]文件末尾开始。
  • option name ‘value’ 定义了一个“名称-值”对 name=value
  • list 定义了一个列表,表示一个名称有多个值,比如这里的 collection 就有 2 个值’first item’和’second item
#下面的例子都是正确的 UCI 语法
option example value
option 'example' value
option example "value"
option "example" 'value' 
option 'example' "value"
#下面的例子都是错误的 UCI 语法
option 'example" "value' (引号不对称)
option example some value with space (缺少引号,引起歧义,不知道哪几个单词相结合)

Vim 语法高亮插件: Vim Editor plugins

UCI 命令

UCI 提供了一个命令行工具 uci,它可以对配置文件中的内容进行修改、添加、删除和读取。
直接输入uci可以查看uci的帮助信息和具体参数

#注:下面说名中 config是配置文件名;section是 对应的name或者id或者@type[0]
# 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>]
	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'

UCI命令含义:

batch

批处理uci命令,需要把每条命令前的字符串”uci”去掉。

#例如在 cfg 配置文件中增加一个section以及option,然后修改section的type与name

uci set cfg.section_name=section_type
uci set cfg.section_name.key=value
uci set cfg.@section_type[0]=section_new_type
uci rename cfg.@section_type[0]=section_new_name
uci export cfg

#只需要把这两个命令去掉uci后放到文档a里面
uci batch << EOI
set cfg.section_name=section_type
set cfg.section_name.key=value
set cfg.@section_type[0]=section_new_type
rename cfg.section_name=section_new_name
export cfg
EOI

#撤销操作
uci revert cfg
#提交 写入cfg 文件中
uci commit cfg
export

uci export [<config>]

显示UCI可读取到的某配置文件的信息(包括已修改但未提交内容)。

# uci export cfg
package cfg

config section_new_type 'section_new_name'
        option key 'value'
import

uci import [<config>]

导入配置文件为UCI格式

# uci import
package cfg
config section_type section_name
option key value
list l 1
list l 2
#ctrl + D

#执行上述命令后会得到文件 cfg
# cat cfg
config section_type 'section_name'
        option key 'value'
        list l '1'
        list l '2'
changes

uci changes [<config>]

# uci changes cfg
cfg.section_name='section_type'
cfg.section_name.key='value'

追踪修改但未提交的动作,类似git。

commit

uci commit [<config>]

提交uci修改,当命令uci changes有返回结果时表示有uci修改待提交,可以通过命令uci commit完成提交,即写入到配置文件。
uci commit可以提交具体的package,例如uci commit network表示只提交network部分的修改。

提交后需要执行相应的命令来重新加载配置,例如:

uci set uhttpd.main.listen_http='8080'
uci commit uhttpd
/etc/init.d/uhttpd restart

通过 uci 写配置文件后,整个配置会被重新写入配置文件,这意味着配置文件中任何无关行都会被删除,包括注释(#开头的内容)。因此如果你要保留自己写的注释,就只能通过文本编辑器修改配置文件。

add

uci add <config> <section-type>

在某个配置文件中添加一条匿名的 section

# uci add cfg section_another_type
cfg02620b #这里是匿名section的id 相当于相当于一个别名,也等同于 @section_another_type[0]
# uci export cfg
package cfg

config section_new_type 'section_new_name'
        option key 'value'

config section_another_type
add_list

uci add_list <config>.<section>.<option>=<string>

添加一条list

# uci add_list cfg.@section_another_type[0].l1=0
# uci add_list cfg.cfg02620b.l1=1
# uci add_list cfg.cfg02620b.l1=2
# uci export cfg
package cfg

config section_new_type 'section_new_name'
        option key 'value'

config section_another_type
        list l1 '0'
        list l1 '1'
        list l1 '2'
del_list

uci del_list <config>.<section>.<option>=<string>

删除一条list,由于list可以存在多个值,所以必须指定删除的值

# uci del_list cfg.@section_another_type[0].l1=1
# uci export cfg
package cfg

config section_new_type 'section_new_name'
        option key 'value'

config section_another_type
        list l1 '0'
        list l1 '2'
show

uci show [<config>[.<section>[.<option>]]]

用压缩格式显示all, package, section或option的值,依参数而定

# uci show                               #--- show all
...

# uci show cfg                           #--- show package
cfg.section_new_name=section_new_type
cfg.section_new_name.key='value'
cfg.@section_another_type[0]=section_another_type
cfg.@section_another_type[0].l1='0' '2'

# uci show cfg.section_new_name          #--- show section
cfg.section_new_name=section_new_type
cfg.section_new_name.key='value'
# uci show cfg.@section_another_type[0]  #--- show section
cfg.cfg02620b=section_another_type
cfg.cfg02620b.l1='0' '2'

# uci show cfg.section_new_name.key      #--- show option
cfg.section_new_name.key='value'
get

uci get <config>.<section>[.<option>]

获取指定 section 的type 或option的值,与uci show等号两边对应

# uci get cfg.cfg02620b
section_another_type
# uci get cfg.@section_another_type[0]
section_another_type
# uci get cfg.section_new_name.key
value
set

uci set <config>.<section>[.<option>]=<value>

设置指定section 的 type 或option的值(不存在则创建该对象),格式可以参考uci show的结果

# uci set cfg.section_new_name.key=val

# uci set cfg.@section_another_type[0]=section_type1
#or
# uci set cfg.cfg02620b=section_type1

# uci export cfg
package cfg

config section_new_type 'section_new_name'
        option key 'val'

config section_type1
        list l1 '0'
        list l1 '2'
delete

uci delete <config>.<section>[.<option>]

删除指定section或option

# uci delete cfg.@section_type1[0].l1
# uci delete cfg.section_new_name 

# uci export cfg
package cfg

config section_type1

# 循环删除
while uci -q delete umdns.@umdns[0]; do :; done
rename

uci rename <config>.<section>[.<option>]=<name>

重命名指定section的name或option的key。

重命名section的name后id就会消失,因为id本质就是别名。

# uci show cfg.@section_type1[0]
cfg.cfg02800c=section_type1
# uci rename cfg.@section_type1[0]=section_name1
# uci show cfg.@section_type1[0]
cfg.section_name1=section_type1

# id 被删除
# uci show cfg.cfg02800c
uci: Entry not found
# uci show cfg.section_name1
cfg.section_name1=section_type1
revert

uci revert <config>[.<section>[.<option>]]

撤销修改(执行uci commit之前)。

# uci changes
-cfg.cfg02800c.l1
-cfg.section_new_name
cfg.cfg02800c='section_name1'
# uci revert cfg
# uci changes cfg
#
reorder

uci reorder <config>.<section>=<position>

修改配置项config在文件中的位置;优先级0最大,数字越大越排后。

# uci batch << EOI
set cfg.name1=type1
set cfg.name2=type2
set cfg.name3=type3
export cfg
EOI

package cfg

config type1 'name1'

config type2 'name2'

config type3 'name3'

# uci reorder cfg.name3=0
# uci export cfg
package cfg

config type3 'name3'

config type1 'name1'

config type2 'name2'

# uci reorder cfg.name1=99
# uci export cfg
package cfg

config type3 'name3'

config type2 'name2'

config type1 'name1'

常用功能配置文件含义(OpenWrt Configuration files):

/etc/config/dhcp        // dnsmasq软件包配置,包含dhcp和dns设置
/etc/config/dropbear    // SSH服务器选项
/etc/config/firewall    // 防火墙设置,包含网络地址转换、包过滤、端口转发等
/etc/config/network     // 网络配置,包含桥接、接口、路由配置
/etc/config/system      // 系统配置,包含主机名称、网络时间同步等
/etc/config/timeserver  // rdate的时间服务列表
/etc/config/luci        // 基本的LuCI配置
/etc/config/wireless    // 无限设置和wifi网络定义
/etc/config/uhttpd      // web服务器选项配置
/etc/config/upnpd       // miniupnpd UPnP服务设置
/etc/config/qos         // 网络服务质量的配置文件定义
通过 shell 脚本操作 UCI 配置

Openwrt 提供了一些 shell 脚本函数,这些函数使得操作 UCI 配置文件变得非常的高效。参考官方
/etc/init.d/目录下的启动脚本基本都会用到(通常脚本开头为#!/bin/sh /etc/rc.common, /etc/rc.common 包含了 /lib/functions.sh)。
要使用这些 shell 函数,首先需要加载 /lib/functions.sh,然后实现 config_cb()、 option_cb()、 list_cb()这些 shell 函数,当我们调用 Openwrt 提供的 shell 函数 config_load 来解析配置文件时,程序就会回调我们自己定义的 config_cb()、 option_cb()、 list_cb() 这些 shell 函数.

下面创建一个 shell 脚本 test.sh,其内容如下:

#!/bin/sh
. /lib/functions.sh

reset_cb

config_cb() {
		local type="$1"
		local name="$2"
		# commands to be run for every section
		if [ -n "$type" ];then
				echo "$name=$type"
		fi
}
option_cb() {
		local name="$1"
		local value="$2"
		# commands to be run for every option
		echo $name=$value
}
list_cb() {
		local name="$1"
		local value="$2"
		# commands to be run for every list item
		echo $name=$value
}

config_load $1

reset_cb 表示将 xxx_cb 这 3 个函数初始化为没有任何操作。config_load 首先从绝对路径文件名加载配置,如果失败再从 /etc/config 路径加载配置文件。xxx_cb 那 3 个函数必须在包含 /lib/functions.sh 和调用 config_load 之间定义。

给 test.sh 添加可执行权限chmod +x test.sh,执行 test.sh

root@OpenWrt:/# ./test.sh dhcp
cfg02411c=dnsmasq
domainneeded=1
boguspriv=1
filterwin2k=0
localise_queries=1
rebind_protection=1
rebind_localhost=1
local=/lan/
domain=lan
expandhosts=1
nonegcache=0
authoritative=1
readethers=1
leasefile=/tmp/dhcp.leases
resolvfile=/tmp/resolv.conf.auto
lan=dhcp
interface=lan
start=100
limit=150
leasetime=12h
wan=dhcp
interface=wan
ignore=1
cfg06fe63=host
ip=192.168.10.104
mac=44:8A:5B:EC:49:27

可以看到,当 config_load 解析配置文件时,解析到 section 时,就会回调 config_cb,解析 option 时,就会回调 option_cb,解析 list 时,就会回调 list_cb。我们可以在对应的函数里面添加自己的相关命令。

另一种方式是使用 config_foreach 针对每一个 section 调用一个指定的自定义的函数,看下面这个 shell 脚本 test.sh

#!/bin/sh
. /lib/functions.sh
reset_cb
handle_interface() {
	local config="$1"
	local custom="$2"
	# run commands for every interface section
	if [ "$config" = "$custom" ];then
		echo $custom
	fi
}
config_load $1
config_foreach handle_interface interface $2

这里定义了一个函数 handle_interface,然后以 handle_interfaceinterface$2 这 3 个参数调用 config_foreach
config_foreach 会遍历以 $1 指定的配置文件中的所有的 section,一旦其类型与参数 interface 相等时,则回调
handle_interface,在 config_foreach 函数内部,会以当前正在解析的 section 的 ID 和调用 config_foreach 时的第 3 个参数作为调用 handle_interface 的参数。

root@OpenWrt:/# ./test.sh network wan
wan

这里以参数 network 和 wan 调用 test.sh,然后程序首先调用 config_load 加载配置文件 network,然后 config_foreach 在配置文件 network 中搜寻类型为 interfacesection,一旦找到就以当前 section 的 ID 和 wan 作为参数调用 handle_interface,在 handle_interface 函数中,得到 config=wan,custom=wan,最终打印出 wan。
使用 config_get 读取配置选项的值,该函数需要至少 3 个参数:

  • 一个存储返回值的变量
  • 要读取的 section 的 ID(如果是有名称的 section 就是其名称)
  • 要读取的 option 的名称

handle_interface 中使用 config_getconfig_set 来读取和设置当前的 section

#!/bin/sh
. /lib/functions.sh
reset_cb
handle_interface() {
	local config="$1"
	local custom="$2"
	# run commands for every interface section
	if [ "$config" = "$custom" ];then
		config_get prot $config proto
		echo $prot
	fi
}
config_load $1
config_foreach handle_interface interface $2
root@OpenWrt:/# ./test.sh network lan
static
root@OpenWrt:/# ./test.sh network wan
dhcp

如果明确知道 section 的名称,可以直接调用 config_get 读取配置选项的值。
config_set 用来设置配置选项的值,它需要 3 个参数:

  • section 的 ID(如果有名称就是其名称)
  • option 的名称 与 要设置的值

更多操作参考

Lua API

lua_bindings_for_uci

  • 6
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值