User Tools

Site Tools


doc:techref:uci

UCI (Unified Configuration Interface) – Technical Reference

What is UCI?

UCI is a small utility written in C (a shell script-wrapper is available as well) and is intended to centralize the whole configuration of a device running OpenWrt. UCI is the successor of the NVRAM based configuration found in the historical OpenWrt branch White Russian and a wrapper for the standard configuration files programs bring with them, like e.g. /etc/network/interfaces, /etc/exports, /etc/dnsmasq.conf, /etc/samba/samba.conf etc.

UCI configuration files are located in the directory /etc/config/
Their documentation can be accessed online in the OpenWrt-Wiki under UCI configuration files.

They can be altered with any text editor or with the command line utility program uci or through various programming APIs (like Shell, Lua and C). The WUI LuCI e.g. uses Lua to manipulate them.

Dependencies of UCI

  • libuci a small library for UCI written in C
    • libuci-lua is a libuci-plugin for Lua which is utilized by e.g. LuCI

Both are maintained in the same git as UCI.

Packages

The functionality is provided by the two packages uci and libuci. The package libuci-lua is also available.

Name Size in Bytes Description
uci 7196 Utility for the Unified Configuration Interface (UCI)
libuci 18765 C library for the Unified Configuration Interface (UCI)
libuci-lua ~6000 libuci-plugin for Lua, e.g. LuCI makes use of it

Installed Files

uci

path/file file type Description
/sbin/uci binary uci executable
/lib/config/uci.sh shell script Shell script compatibility wrappers for /sbin/uci

libuci

path/file file type Description
/lib/libuci.so symlink symlink to libuci.so.xxx
/lib/libuci.so.2011-01-19 binary Library

libuci-lua

path/file file type Description
/usr/lib/lua/uci.so binary Library

Lua Bindings for UCI

For those who like lua, UCI can be accessed in your code via the package libuci-lua. Just install the package then, in your lua code do

require("uci")

API

The api is quite simple

top level entry point

uci.cursor() (that instantiates a uci context instance) e.g.

x = uci.cursor()
or
x = uci.cursor(nil, "/var/state")
if you want to involve state vars

on that you can call the usual operations

x:get("config", "sectionname", "option")
returns string or nil for not found
x:set("config", "sectionname", "option", "value")
sets simple string value
x:set("config", "sectionname", "option", { "foo", "bar" })
sets list value
x:delete("config", "section", "option")
deletes option
x:delete("config", "section")
deletes section
x:add("config", "type")
adds new anon section "type" and returns its name
x:set("config", "name", "type")
adds new section "name" with type "type"
x:foreach("config", "type", function(s) ... end)
iterates over all sections of type "type" and invokes callback function for each "s" within the callback. s is a table containing all options and two special properties

  • s['.type'] → section type
  • s['.name'] → section name

If the callback function returns false [NB: not nil!], foreach() will terminate at that point without iterating over any remaining sections. foreach() returns true if at least one section exists and the callback function didn't raise an error for it; false otherwise.

x:reorder("config", "sectionname", position)
Move a section to another position. Position starts at 0. This is for example handy to change the wireless config order (changing priority).
x:revert("config")
discards any changes made to the configuration, that have not yet been committed
x:commit("config")
commits (saves) the changed configuration to the corresponding file in /etc/config

That's basically all you need

About uci structure

It took me some time to understand the difference between "section" and "type". Let's start with an example:

#uci show system
system.@system[0]=system
system.@system[0].hostname=OpenWrt
system.@system[0].timezone=UTC
system.@rdate[0]=rdate
system.@rdate[0].server=ac-ntp0.net.cmu.edu ptbtime1.ptb.de ac-ntp1.net.cmu.edu ntp.xs4all.nl ptbtime2.ptb.de cudns.cit.cornell.edu ptbtime3.ptb.de

Here, x:get("system","@rdate[0]","server") won't work. rdate is a type, not a section.

Here is the return of x:get_all("system"):

{
 cfg02f02f={[".name"]="cfg02f02f",[".type"]="system",hostname="OpenWrt",[".index"]=0,[".anonymous"]=true,timezone="UTC"},
 cfg04e10c={[".name"]="cfg04e10c",[".type"]="rdate",[".index"]=1,[".anonymous"]=true,server={"ac-ntp0.net.cmu.edu","ptbtime1.ptb.de","ac-tp1.net.cmu.edu","ntp.xs4all.nl","ptbtime2.ptb.de","cudns.cit.cornell.edu","ptbtime3.ptb.de"}}
}

[".type"] gives the type of the section

[".name"] gives the real name of the section. You can see here, that these names are generated.

[".index"] is the index of the list (+1)

From what I know, there seem to be no way to access "@rdate[0]" directly. You have to iterate with x:foreach to list all the elements of a given type.

I use the following function:

uci=require("uci")
function getConfType(conf,type)
   local curs=uci.cursor()
   local ifce={}
   curs:foreach(conf,type,function(s) ifce[s[".index"]]=s end)
   return ifce
end

getConfType("system","rdate") returns:

{{[".name"]="cfg04e10c",[".type"]="rdate",[".index"]=1,[".anonymous"]=true,server={"ac-ntp0.net.cmu.edu","ptbtime1.ptb.de","ac-ntp1.net.cmu.edu","ntp.xs4all.nl","ptbtime2.ptb.de","cudns.cit.cornell.edu","ptbtime3.ptb.de"}}}

So if you want to modify system.@rdate[0].server you need to iterate the type then retreive the section name ([".name"]) then call x:set("system","cfg04e10c","server","zzz.com")

Hope this helps

Sophana

(Luci has however a Cursor:get_first function that is similiar to get except it takes a type instead as section as second argument.)

Additional Information

See also LuCI UCI model functions. Thats what LuCI uses. It extends the uci cursor class with a few more convenience functions.


Usage outside of OpenWrt

If you want to use the libuci apart from OpenWrt (for e.g. you are developing an application in C on your host computer) then prepare as follows:

Grab the source.

git clone git://nbd.name/uci.git

Go to the source directory (where the CMakeLists.txt lives) and configure the build without Lua bindings:

cd uci/; cmake -D BUILD_LUA:BOOL=OFF .

Build and install uci als root (this will install uci into /usr/local/, see this thread on how to install and use uci without root permissions in your home directory: https://forum.openwrt.org/viewtopic.php?id=40547):

make install

Open /etc/ld.so.conf and add the place where you installed the uci library:

vi /etc/ld.so.conf

Add this line somewhere to /etc/ld.so.conf

/usr/local/lib

Execute ldconfig as root to apply the changes to /etc/ld.so.conf

ldconfig

To compile your application you have to link it against the uci library. Append -luci in your Makefile:

$(CC) test.o -o test -luci

And examples on how to use UCI in C can be found in this thread: https://forum.openwrt.org/viewtopic.php?pid=183335#p183335 To get more examples look into the source directory of uci which you got by git clone and open cli.c or ucimap-example.c

Functioning

All uci set, uci add, uci rename and uci delete commands are staged in /tmp and written to flash at once with uci commit. This obviously does not apply to people using text editors, but to scripts, guis and other programs working with uci files.

doc/techref/uci.txt · Last modified: 2013/09/04 15:58 by peteruithoven