Skip to content

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 软件为例):

  1. 启动脚本 /etc/init.d/samba
  2. 启动脚本通过 UCI 分析库从 /etc/config/samba 获得启动参数
  3. 启动脚本完成正常启动

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 [<option>] <command> [<arguments>]

读取类语法

命令 说明
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
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_foreachconfig_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