Why is uci-defaults recommended over replacing config files

I'm building my own custom firmware for the BananaPI BPI-R4, so I have my whole network and other settings in the image and also in my git repository as backup and source of truth.

I went with the recommendation in the wiki to use uci-defaults, but it seems so tedious to write those scripts. And the reason is not the configuration itself, because that's basically 1:1 conversion from config file to uci command line. But dealing with the existing default configuration of the device.

The argument for uci-defaults instead of config files was that it is easier to respect existing configuration or things that change with new OpenWrt releases.

For me it seems though, that it would be easier to just copy the defaults (like firewall defaults, loopback network) into the config file and then add my configuration on top, resulting in the final config files.

Does this make sense? Or what am I missing?

uci-defaults run exactly once after config reset or restore or sysupgrade.

That is correct, but how does this help me with my question?

You can use config files also.

But then you are only another user here that reuse your old config files over and over again for like ten years and finally everything stop working because the original config files are completely rewritten and you have no clue what is happening.

Okay, that helps me a bit more.

So, you mean over time the config file format changes and thus my config files don't adapt to those changes, because I'm not using uci to write them?

How would I deal with the default board configuration with uci?

To give some examples. I want to setup my own network config. Removing or overwriting the existing configuration that comes with the board. In this case a bridge for the 4 lan ports and a bridge for the 2 wan ports. For that I would need to delete them, but then I also need to know, what their names are in if the board config changes, my scripts will fail. The only config I wouldn't change is network.loopback and network.globals.

Now as I don't want to assume the default config, to delete the right entries, I'd rather delete the whole network part, then add the loopback and globals back and then add my network config afterwards for wan, wifi, private and guest network and so on.

And then I was wondering why I would use uci for that, if I could just put the whole file down instead.

Is my description and thought process understandable?

Short update. I managed to build my image and load it on the R4.

It's even worse than I thought. My uci-defaults are basically useless, because there is some other initialization running for the board after my scripts, even though I used 900, 910, and 911 as prefixes for the files.

Where do those configuration steps come from? Are they part of the board config?

Edit: Found my mistake. Can't just run uci delete firewall to reset the config :sweat_smile:

Start by making a setup script that actually work on standard install to begin with.
If you build a faulty setup scripts in the firmware, what is your backup plan because you will never get in to the router again without serial connection?

uci-defaults can be used for surgical alterations of the things you want changing, while conffile replacements do just that, ignoring changes in parts of the file that might need changing/ don't affect your intentions.

Both are valid options, but uci-defaults has a higher chance to keep working without (or with minimal-) adaptions between multiple 'normal' major version upgrades.

exactly.

Its a matter of preference. However, if you have multiple files, its usually preferred to only have to make changes in 1 file, opposed to each file individually. This method also makes maintaining and tracking changes much more convenient.

I very much doubt it. MAY_BE during start of certain services, some settings are changed, although I never saw this.
However, I extensively use just one settings.sh in .../uci-defaults, to modify small portions of the default config files, i.e. "uci set system.@system[0].log_ip='1.2.3.4'" Or to /etc/init.d/service disable; /etc/init.d/service stop , to start this service explicitly from rc.local later on.
For larger changes, I either do something like 'cat myadditions >> /etc/config/network'
OR I even replace the standard config file completely.
Thus, the method I use depends upon the amount of changes required.
Finally, in certain cases, I completely wipe out all traces of default installation of a package, and manage everything myself, "The standard LINUX way". Best example here is squid: Explicit start in customized rc.local; squids config completely in /etc/squid/squid.conf .

3 Likes

Some files (network, wifi for example if I remember correctly) are generated on first boot, so if you use uci-defaults scripts properly, those would be more portable between different devices than just straight up config files.

2 Likes

There is no case to be made for replacing your configuration files wholesale. Consider for a moment that the configuration files in /etc/config/ are generated based on the UCI settings, not the other way around. The configuration files are merely a human readable translation of those.

Anything outside /etc/config/ can be replaced completely, (e.g. /etc/hosts) since UCI is not involved there.