UCI is Fairly Useless

I'd like UCI to add only those options which don't exist and sort all options within each section.

Every time UCI settings are changed they seem to occur in random order. This makes it impossible to do a simple file compare to find the differences. UCI also adds duplicates of settings.

Many years ago win3 used ini files (which are essentially the same thing) and ini editors were much smarter.

Maybe I need to write changes to a file then use the -m option to merge the file.

Yes, I could believe it's hard to read/write UCI config files. But there's hope. You can use the UCI command line to make changes only to the lines you want. There's a brief outline of using UCI to do this in OpenWRT SSID Creation

I agree that is a good example of how limited UCI is, similar to my example which starts at # enablebasicgui.sh.

I'd like a good workaround. Preferred functionality - if section doesn't exist add it, if section exists update it. There are a couple of problems:

  1. It is not practical to use if for every line and if test used for missing sections then existing section settings not updated
  2. With a set command (eg uci set web.helptraffic.roles='admin' IIRC) the setting wont be duplicated but existing list settings will be deleted.

Any thoughts on ordering the config file to help compare changes?

Hmmm... Your example shows that you know more about this than I do, so I'll back away slowly... :slight_smile:

What happens when you use the reorder argument?

https://openwrt.org/docs/guide-user/base-system/uci

Agree - looks interesting.

Usage: uci [<options>] <command> [<arguments>]
Commands:
reorder <config>.<section>.<position>

Not much guidance: Description ... todo

Any examples? (Mine failed.)

https://wiki.openwrt.org/doc/techref/uci

Move a section to another position. Position starts at 0. This is for example handy to change the wireless config order (changing priority).

Not really what I'm looking for.

I agree, that sorting is often convenient.
But the problem is more complicated than it seems.
Some configuration could depend on options order.
Some other could depend on sections order.
So it's impossible to apply sorting by default, otherwise it would break things.
Possible solution is providing a command uci sort [<config>].


Adding duplicates could also be useful.
May be not by default, but with some option like -D, --allow-duplicates.


Diff is actually missing.
And that's especially frustrating when you want to compare modified configuration with default one including custom formatting and comments.
It not only requires diffutils but also additional work to unify the formatting.

1 Like

Also UCI does not handle comments.

A bit OT but I have used augeas, it can handle a plethora of unix/linux config files, and it would probably be easy to add UCI files to it. It does not reorder stuff, handles comments etc. But the footprint is (without really knowing) probably too large for a router. But for a larger system it's a nice tool to update config files from shell scripts etc.

Yep, that's one of the reasons why I never use LuCI or UCI to modify my configs.

@vgaetera +1

Large changes to order for small changes to settings are meaningless.

Default as no duplicates would be a useful start.

I find uci useful only for manual control or simple scrips.

Quite a few times I've had to have a script go and parse uci files in /etc/config/ directly with sed and awk (it's pretty easy, due to their syntax) and then run uci commit && reload_config to have the system load the changed configs.

You did it wrong then :wink: There's no single sane reason I can think of why that would be preferable over the shell API.

I agree that a sed/awk substitution approach would retain comments but since you mentioned uci commit (which rewrites and reformats the files) that couldn't have been the motivation.

UCI useless? Replace it with ini files? What in the name of the lord is going on here? :stuck_out_tongue:

I find it very useful, here's how I use it to preconfigure my router image for example:

Thanks @escalade - Do you have any comments on any issues in the first (or third) post? Perhaps those raised by vgaetera.

Can you elaborate on that? Do you mean that you do not want a uci set foo.bar.baz=qrx to end up in the changes list of that option already was set to qrx?

This sounds like something that can be addressed by introducing a specialized uci diff command.

Can you try to better explain what you mean with this?

If it already exists it adds it again, ie duplicates it.

Maybe - A consistent order (unless changed for a reason) is important to me to allow comparing files from two configurations outside the modem with np++.

That cannot be.

root@OpenWrt:~# echo "config testsection testsection" > /etc/config/testconfig
root@OpenWrt:~# uci set testconfig.testsection.testoption=foo
root@OpenWrt:~# uci commit testconfig
root@OpenWrt:~# cat /etc/config/testconfig 

config testsection 'testsection'
	option testoption 'foo'

root@OpenWrt:~# uci set testconfig.testsection.testoption=foo
root@OpenWrt:~# uci commit testconfig
root@OpenWrt:~# cat /etc/config/testconfig 

config testsection 'testsection'
	option testoption 'foo'

root@OpenWrt:~# 

Can you provide a specific example on what you mean exactly? It is not possible to create duplicate options through the uci set command, I'm sure you're referring to something else.

From this example:

uci add_list web.ruleset_main.rules='broadband'
uci set web.broadband=rule
uci set web.broadband.target='/broadband.lp'
uci add_list web.broadband.roles='admin'
uci add_list web.broadband.roles='engineer'

Running multiple times adds multiple web.ruleset_main.rules and web.broadband.roles.

(BTW - Running Chaos Calmer 15.05.1 under BusyBox v1.23.2)

Ah okay, so your problem is with add_list and not set. I guess it boils down to the way how add_list is defined as operation. It is supposed to merely append its value as item to a collection.

To make the example above idempotent, you'd need something like:

uci del_list web.ruleset_main.rules='broadband'
uci add_list web.ruleset_main.rules='broadband'
uci set web.broadband=rule
uci set web.broadband.target='/broadband.lp'
uci del_list web.broadband.roles='admin'
uci add_list web.broadband.roles='admin'
uci del_list web.broadband.roles='engineer'
uci add_list web.broadband.roles='engineer'

This is actually quite like e.g. iptables works. Invoking iptables -I ... or iptables -A ... multiple times will also results in duplicate rules unless each -A or -I is preceeded by a matching -D.

So what is needed to address your particular problem here is a new cli operation, e.g. replace_list conf.sect.opt=val (or maybe set_list is a better fitting name), which is defined as "append val to the list at conf.sect.opt unless the list already contains an item val".