openwrt - uci¶
UCI 命令系统¶
UCI (Unified Configuration Interface) 是 OpenWrt 中配置参数管理系统,UCI 中已经包含了网络配置、无线配置、系统信息配置等基本路由器所需的主要配置参数。
UCI 配置文件全部存储在 /etc/config
目录下:
root@Thingoo:/# ls /etc/config/
dhcp fstab mountd shairport uhttpd
dropbear luci network system wireless
firewall mjpg-streamer rpcd ucitrack
常见的 UCI 配置:
配置文件 | 作用 |
---|---|
/etc/config/dhcp | 面向 LAN 口提供的 IP 地址分配服务配置 |
/etc/config/dropbear | SSH 服务配置 |
/etc/config/firewall | 路由转发,端口转发,防火墙规则 |
/etc/config/network | 自身网络接口配置 |
/etc/config/system | 时间服务器时区配置 |
/etc/config/wireless | 无线网络配置 |
支持 UCI 管理模式的软件包是这样完成启动的(以 samba 软件为例):
- 启动脚本
/etc/init.d/samba
- 启动脚本通过 UCI 分析库从
/etc/config/samba
获得启动参数 - 启动脚本完成正常启动
UCI 配置文件既可以使用 UCI 命令进行修改,也可以使用文本编辑器直接修改。但如果两种方式都使用,需要注意 UCI 命令修改会产生缓存,每次修改好要尽快保存确认,以免出现冲突。
UCI 文件格式¶
config 'section-type' 'section'
option 'key' 'value'
option 'list_key' 'list_value1'
option 'list_key' 'list_value2'
UCI 允许只有 section-type 的匿名配置节点。
UCI 命令读写配置¶
读取类语法¶
命令 | 说明 |
---|---|
uci get \<config>.\<section> | 获取节点类型 |
uci get \<config>.\<section>.\<option> | 获取取得一个值 |
uci show | 显示全部 UCI 配置 |
uci show <config> | 显示指定文件配置 |
uci show <config>.\<section> | 显示指定节点的配置 |
uci show \<config>.\<section>.\<option> | 显示指定选项配置 |
uci changes <config> | 显示尚未生效的修改记录 |
uci show -X \<config>.\<section>.\<option> | 显示匿名节点 |
写入类语法¶
命令 | 说明 |
---|---|
uci add \<config> \<section-type> | 增加一个匿名节点 |
uci set \<config>.\<section> = \<section-type> | 增加一个节点/修改节点类型 |
uci set \<config>.\<section>.\<option> = \<value> | 增加一个选项值/修改一个选项值 |
uci add_list \<config>.\<section>.\<option> = \<value> | 在列表中增加一个值 |
uci delete <config>.\<section> | 删除指定节点 |
uci delete <config>.\<section>.\<option> | 删除指定选项 |
uci delete <config>.\<section>.\<list> | 删除列表 |
uci del_list \<config>.\<section>.\<option> = \<string> | 删除列表中的一个值 |
uci commit <config> | 使修改生效 |
UCI 读取总是先读取内存中的缓存,然后再读取文件中的。进行过增删改操作后要执行生效指令,否则所有的修改只留存在缓存中。
通过 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
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_interface
、interface
和 $2
这 3 个参数调用 config_foreach
。 config_foreach
会遍历以 $1
指定的配置文件中的所有的 section
,一旦其类型与参数 interface
相等时,则回调 handle_interface
,在 config_foreach
函数内部,会以当前正在解析的 section
的 ID 和调用 config_foreach
时的第 3 个参数作为调用 handle_interface
的参数。 这里以参数 network 和 wan 调用 test.sh,然后程序首先调用 config_load
加载配置文件 network
,然后 config_foreach
在配置文件 network 中搜寻类型为 interface
的 section
,一旦找到就以当前 section
的 ID 和 wan 作为参数调用 handle_interface
,在 handle_interface
函数中,得到 config=wan,custom=wan
,最终打印出 wan。 使用 config_get 读取配置选项的值,该函数需要至少 3 个参数: - 一个存储返回值的变量
- 要读取的 section 的 ID(如果是有名称的 section 就是其名称)
- 要读取的 option 的名称
在 handle_interface
中使用 config_get
和 config_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
config_get
读取配置选项的值。 config_set
用来设置配置选项的值,它需要3个参数: - section 的 ID(如果有名称就是其名称)
- option 的名称 与 要设置的值