User Tools

Site Tools


doc:techref:uci

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
doc:techref:uci [2013/07/03 11:05]
lorema
doc:techref:uci [2016/03/04 11:24] (current)
nemesis [lua methods] Provided some real world examples and improved formatting for readability
Line 1: Line 1:
 +====== UCI (Unified Configuration Interface) – Technical Reference ======
  
 +  * [[http://​git.openwrt.org/?​p=project/​uci.git;​a=summary|Project'​s git: UCI (Unified Configuration Interface) library and utility]]
 +  * UCI is available in OpenWrt since [[https://​dev.openwrt.org/​changeset/​10367|R10367 (trunk)]]
 +  * Use ''​git''​ on your local GNU/Linux installation to retrieve the source code:<​code bash>
 +git clone https://​git.openwrt.org/​project/​uci.git
 +</​code>​
 +  * This is the Technical Reference. Please see **[[doc/​uci|UCI (Unified Configuration Interface) – Usage]]**
 +
 +==== What is UCI? ====
 +''​UCI''​ is a small utility written in [[wp>C (programming language)|C]] (a [[wp>​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 [[about:​history|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.
 +
 +| {{:​meta:​icons:​tango:​dialog-information.png?​nolink}} | UCI configuration files are located ​ in the directory **''/​etc/​config/''​**\\ Their documentation can be accessed online in the OpenWrt-Wiki under [[doc:​uci|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 [[doc:​techref:​LuCI]] e.g. uses Lua to manipulate them.
 +
 +==== Dependencies of UCI ====
 +  * ''​libuci''​ a small library for UCI written in [[wp>C (programming language)|C]]
 +    * ''​libuci-lua''​ is a libuci-plugin for [[wp>Lua (programming language)|Lua]] which is utilized by e.g. [[doc:​techref:​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 [[wp>Lua (programming language)|Lua]],​ e.g. [[doc:​techref:​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 <code lua>​require("​uci"​)</​code>​
 +
 +===== API =====
 +The api is quite simple
 +
 +==== top level entry point ===
 +uci.cursor() instantiates a uci context instance, e.g:
 +
 +<code lua>x = uci.cursor()</​code>​
 +
 +if you want to involve state vars:
 +
 +<code lua>x = uci.cursor(nil,​ "/​var/​state"​)</​code>​
 +
 +
 +if you need to work on UCI config files that are located in a non standard directory:
 +
 +<code lua>
 +x = uci.cursor("/​etc/​mypackage/​config",​ "/​tmp/​mypackage/​.uci"​)
 +</​code>​
 +==== on that you can call the usual operations ====
 +
 +Get value (returns ''​string''​ or ''​nil''​ if not found):
 +
 +<code lua>
 +x:​get("​config",​ "​sectionname",​ "​option"​)
 +
 +-- real world example:
 +x:​get("​network",​ "​lan",​ "​proto"​)
 +</​code>​
 +
 +Set simple string value:
 +
 +<code lua>
 +x:​set("​config",​ "​sectionname",​ "​option",​ "​value"​)
 +
 +-- real world example:
 +x:​set("​network",​ "​lan",​ "​proto",​ "​dhcp"​)
 +</​code>​
 +
 +Set list value:
 +
 +<code lua>
 +x:​set("​config",​ "​sectionname",​ "​option",​ { "​foo",​ "​bar"​ })
 +
 +-- real world example:
 +x:​set("​system",​ "​ntp",​ "​server",​ {
 +  "​0.openwrt.pool.ntp.org",​
 +  "​1.openwrt.pool.ntp.org",​
 +  "​2.openwrt.pool.ntp.org",​
 +  "​3.openwrt.pool.ntp.org"​
 +})
 +</​code>​
 +
 +Delete option:
 +
 +<code lua>
 +x:​delete("​config",​ "​section",​ "​option"​)
 +
 +-- real world example:
 +x:​delete("​network",​ "​lan",​ "​force_link"​)
 +</​code>​
 +
 +Delete section:
 +
 +<code lua>
 +x:​delete("​config",​ "​section"​)
 +
 +-- real world example:
 +x:​delete("​network",​ "​wan6"​)
 +</​code>​
 +
 +Add new anonymous section "​type"​ and return its name:
 +
 +<code lua>
 +x:​add("​config",​ "​type"​)
 +</​code>​
 +
 +<code lua>
 +> -- real world example from interpreter:​
 +> name = x:​add("​network",​ "​switch"​)
 +> print(name)
 +cfg0e3777
 +</​code>​
 +
 +Add new section "​name"​ with type "​type":​
 +
 +<code lua>
 +x:​set("​config",​ "​name",​ "​type"​)
 +
 +-- real world example:
 +x:​set("​network",​ "​wan6",​ "​interface"​)
 +</​code>​
 +
 +Iterate over all section of type "​type"​ and invoke a callback function:
 +
 +<code lua>​x:​foreach("​config",​ "​type",​ function(s) ... end)</​code>​
 +
 +In the preceding example, 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.
 +
 +Here's another example:
 +
 +<code lua>
 +> -- real world example from interpreter:​
 +> x:​foreach("​system",​ "​led",​ function(s)
 +>> ​    ​print('​------------------'​)
 +>> ​    for key, value in pairs(s) do
 +>> ​        ​print(key .. ': ' .. tostring(value))
 +>> ​    end
 +>> end)
 +------------------
 +dev: 1-1.1
 +.anonymous: false
 +trigger: usbdev
 +.index: 2
 +name: USB1
 +interval: 50
 +.name: led_usb1
 +.type: led
 +sysfs: tp-link:​green:​usb1
 +------------------
 +dev: 1-1.2
 +.anonymous: false
 +trigger: usbdev
 +.index: 3
 +name: USB2
 +interval: 50
 +.name: led_usb2
 +.type: led
 +sysfs: tp-link:​green:​usb2
 +------------------
 +.name: led_wlan2g
 +.type: led
 +name: WLAN2G
 +trigger: phy0tpt
 +sysfs: tp-link:​blue:​wlan2g
 +.anonymous: false
 +.index: 4
 +</​code>​
 +
 +Move a section to another position. Position starts at 0. 
 +This is for example handy to change the wireless config order (changing priority). ​
 +
 +<code lua>​x:​reorder("​config",​ "​sectionname",​ position)</​code>​
 +
 +Discard any changes made to the configuration,​ that have not yet been committed:
 +
 +<code lua>​x:​revert("​config"​)</​code>​
 +
 +commits (saves) the changed configuration to the corresponding file in ''/​etc/​config''​
 +
 +<code lua>​x:​commit("​config"​)</​code>​
 +
 +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:
 +
 +<​code>#​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
 +</​code>​
 +
 +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"​)'':​
 +
 +<code lua>
 +{
 +  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"​
 +    }
 +  }
 +}
 +</​code>​
 +
 +''​["​.type"​]''​ gives the type of the section;
 +
 +''​["​.name"​]''​ gives the real name of the section (note that these names are auto-generated);​
 +
 +''​["​.index"​]''​ is the index of the list (starting from 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:
 +
 +<code lua>
 +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
 +</​code>​
 +
 +''​getConfType("​system","​rdate"​)''​ returns:
 +
 +<code lua>
 +{
 +  {
 +    ["​.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"​
 +    }
 +  }
 +}
 +</​code>​
 +
 +So if you want to modify ''​system.@rdate[0].server''​ you need to iterate the type, retrieve the section name ''​["​.name"​]''​ and then call:
 +
 +<code lua>​x:​set("​system","​cfg04e10c","​server","​zzz.com"​)</​code>​
 +
 +Hope this helps.
 +
 +Sophana
 +
 +(Luci has however a [[http://​luci.subsignal.org/​api/​luci/​modules/​luci.model.uci.html#​Cursor.get_first|Cursor:​get_first]] function that is similiar to get except it takes a type instead as section as second argument.)
 +
 +===== Additional Information =====
 +
 +See also [[http://​luci.subsignal.org/​api/​luci/​modules/​luci.model.uci.html|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.
 +<​code>​git clone https://​git.openwrt.org/​project/​uci.git
 +</​code>​
 +
 +Go to the source directory (where the CMakeLists.txt lives) and optionally configure the build without Lua bindings:
 +<​code>​cd uci/; cmake [-D BUILD_LUA:​BOOL=OFF] .</​code>​
 +
 +Build and install uci as 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):​
 +<​code>​make install</​code>​
 +
 +Open /​etc/​ld.so.conf and add the place where you installed the uci library:
 +<​code>​vi /​etc/​ld.so.conf</​code>​
 +
 +Add this line somewhere to /​etc/​ld.so.conf
 +<​code>/​usr/​local/​lib</​code>​
 +
 +Execute ldconfig as root to apply the changes to /​etc/​ld.so.conf
 +<​code>​ldconfig</​code>​
 +
 +To compile your application you have to link it against the uci library. Append -luci in your Makefile:
 +<​code>​$(CC) test.o -o test -luci</​code>​
 +
 +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.
 +
 +{{tag>​wip}}