Az OpenWrt által kínált standard shell procedúrák segítségével az UCI konfigfájlok beállításai hatékonyan kiolvashatóak és kezelhetőek shell scriptekből is. Ezek a shell wrapper-ek ugyanúgy az uci parancssori segédprogramot használják, de számos funkcióval megkönnyítik a használatát.
Hogy használni tudd az általános UCI procedúrákat, mindenek előtt includolni kell a /etc/functions.sh fájlt a scriptedbe az alábbi paranccsal (általában ez csak egy symlink a ../lib/functions.sh-ra):
. /etc/functions.sh |
Ezután a config_load name
hívással tölthetsz be egy adott UCI beállításfájlt.
Ez a funkció előbb ellenőrzi, hogy a name
abszolút elérési út-e, és ha nem, akkor alapértelmezetten a
/etc/config/
mapppából próbálja betölteni a filet (általában így szokás használni).
A UCI beállítások legegyszerűbben ezzel a módszerrel érhetők el.
Ha előre ismert a section neve, akkor a benne lévő option-ok értékei szekvenciális feldolgozás alkalmazása nélkül, közvetlenül is elérhetőek.
Ehhez a config_get
és config_set
függvényeket kell használni.
Konkrét opciók beolvasására a config_get használható. Két féle paramétezése van:
Használata (teljes): config_get <variable> <section> <option> [<default>]
Ekkor a config_get
procedúra legalább három paramétert vár:
Használata (egyszerűsített): config_get <section> <option>
Egyszerű elérésnél a paraméterek a következők:
Az alábbi példaprogram a “loopback” hálózati interfész IP-címét olvassa be (ez alapesetben 127.0.0.1) előbb sikeresen, majd az option nevét elrontva sikertelenül, majd újra sikeres az egyszerűbb módszerrel:
#!/bin/sh . /etc/functions.sh local loopbackIP config_load network config_get loopbackIP loopback ipaddr echo The loopback IP is: "$loopbackIP" echo "trying to read a non-existant value results default value:" config_get loopbackIP loopback ipaddress "invalid option" echo The loopback IP is: "$loopbackIP" echo "reading with the simple method:" loopbackIP=$(config_get loopback ipaddr) echo The loopback IP is: "$loopbackIP"
Eredmény:
# ./UCIgetloopbackip.sh
The loopback IP is: 127.0.0.1
trying to read a non-existant value results default value:
The loopback IP is: invalid option
reading with the simple method:
The loopback IP is: 127.0.0.1 |
Ha előre tudjuk hogy egy logikai típusú option-t szeretnénk beolvasni, akkor használjuk a config_get_bool
függvényt.
A logikai konfigurációs értékek elég változatosak lehetnek, az igaz értéket a következők bármelyike jelölheti on
, true
, enabled
vagy 1
.
A hamis érték off
, false
, disabled
vagy 0
is lehet.
The config_get_bool
leegyszerűsíti ezek kezelését azáltal, hogy sima integerré konvertálja őket (1
lesz az igaz és 0
a hamis érték).
Használata: config_get_bool <variable> <section> <option> [<default>]
A paraméterei ugyanazok mint a config_get-nek:
A lista típusú UCI option-ök több értéket tárolnak ugyanazzal a névvel. Például az alábbi network nevű listának két eleme van:
...
list network lan
list network wifi
... |
A config_get
használata listák eléréséhez nem mindig célravezető, mivel a lista összes elemét összefűzve, szóközzel elválasztva adja vissza.
A fenti network
listánál ez nem okoz különösebb gondot az eredmény: lan wifi
.
Viszont kicsit bonyolultabb a helyzet ha a lista elemei maguk is tartalmaznak szóközt, például:
...
list animal 'White Elephant'
list animal 'Mighty Unicorn'
... |
Ekkor config_get
a következő értéket adja vissza: White Elephant Mighty Unicorn
és ez alapján nem lehet eldönteni, hogy meddig tartott az első, és hol kezdődik a második elem.
A probléma megoldására a config_list_foreach
iterátor használható. Ez hasonlóan működik, mint a config_foreach
(lásd később), csak a section-ök helyett a lista értékeit kezeli.
Használatához először egy saját callback függvényt kell definiálni, ami paraméterben fogja egyesével megkapni a lista értékeit, minden egyes lista értéknél újra meghívódik.
A config_list_foreach
legalább három paramétert vár:
Például
# handle list items in a callback
# $config contains the ID of the section
handle_animal() {
local value=“$1”
# do something with $value
}
config_list_foreach “$config” animal handle_animal |
Teljes példaprogram, az NTP szerverek kiíratása:
#!/bin/sh . /etc/functions.sh counter=0 handle_listvalue() { local value="$1" local custom="$2" echo The $counter. value of the list is $value counter=$((counter+1)) } config_load system echo "value of ntp.server list by using config_get:" config_get ntp server echo "values using the config_list_foreach iterator:" config_list_foreach ntp server handle_listvalue
Eredmény:
# ./UCIlistiterator.sh
value of ntp.server list by using config_get:
0.openwrt.pool.ntp.org 1.openwrt.pool.ntp.org 2.openwrt.pool.ntp.org 3.openwrt.pool.ntp.org
values using the config_list_foreach iterator:
The 0. value of the list is 0.openwrt.pool.ntp.org
The 1. value of the list is 1.openwrt.pool.ntp.org
The 2. value of the list is 2.openwrt.pool.ntp.org
The 3. value of the list is 3.openwrt.pool.ntp.org |
A beállítások szekvenciális feldolgozására akkor van szükség,
Erre két féle módszer használható: a visszahívásos módszer (callback) és az utólagos iteráció.
Ha a callback módszert szeretnéd használni a beállítások feldolgozásához, akkor ehhez felül definiálni kell bizonyos shell függvényeket
a /etc/functions.sh
includolása után, de még a config_load
hívása előtt.
Ebben az esetben a keretscript a konfigfájlt soronként olvassa be és minden sorhoz meghívja a hozzá tartozó callback függvényt:
config
kulcsszónál a config_cb
option
kulcsszónál az option_cb
list
kulcsszó esetén pedig a list_cb
fut le.
Ezeket nekünk kell definiálni a scriptünkben a config_load
hívása előtt. (Alapesetben ezek a függvények nem csinálnak semmit, mindössze egy return 0-val visszatérnek.)
A callback függvényeken belül az aktuális section ID-je a $CONFIG_SECTION
változóban érhető el.
A feldolgozás során minden új UCI section kezdeténél (config kulcsszónál) meghívódik a config_cb
függvény.
A config_cb
ebben az esetben két paramétert kap:
config interface wan
sor esetén az interface
.config interface wan
sornál a wan
, vagy anonymous section-ök esetén (pl. config route
) egy automatikusan generált ID lesz, pl. cfg13abef
. config_cb() {
local type=“$1”
local name=“$2”
# echo New section - type: “$type”, name: “$name”
# minden section esetén futtatandó parancsok
} |
A config_load
függvény végén egy további, paraméterek nélküli config_cb
hívás is történik, így nem csak az option-ok előtt hanem az összes section feldolgozása után is hajthatsz végre saját parancsokat. Számíts rá, hogy ilyenkor a paramétereknek nem lesz értéke, szűrd ki az esetet pl. egy if-fel.
Hasonló módon, minden egyes új option sor elérésekor az option_cb
függvény hívódik meg.
Az option_cb
mindig két paramétert kap:
ifname
az option ifname eth0
sor eseténeth0
az option ifname eth0
sor esetén option_cb() {
local name=“$1”
local value=“$2”
# echo new option - name: “$name”, value: “$value”
# minden option esetén futtatandó parancsok
} |
Az option_cb
függvényt a config_cb
függvényből is módosíthatod a section típusa szerint.
Így lehetőség van típusonként külön option_cb
függvényt alkalmazva minden egyes config section-t a saját típusának megfelelően feldolgozni.
A harmadik kulcsszó sem kivétel, minden egyes új list sor elérésekor a list_cb
függvény fut le. Mivel minden egyes lista elem külön list
sorban van, így a függvény elemenként egyszer lesz meghívva. Ugyanazon lista elemeinek ugyanaz a nevük.
Az list_cb
mindig két paramétert kap:
icmp_type
a list icmp_type echo-reply
sor eseténecho_reply
a list icmp_type echo-reply
sor esetén list_cb() {
local name=“$1”
local value=“$2”
# echo new list element - name: “$name”, value: “$value”
# minden list esetén futtatandó parancsok
} |
Írassuk ki a default system configot! A teszt pillanatában nekem így nézett ki a /etc/config/system fájl:
config system
option hostname OpenWrt
option timezone UTC
config timeserver ntp
list server 0.openwrt.pool.ntp.org
list server 1.openwrt.pool.ntp.org
list server 2.openwrt.pool.ntp.org
list server 3.openwrt.pool.ntp.org
option enable_server 0 |
Az alábbi példaprogram segítségével élesben is tesztelheted a callback függvények működését. Mentsd el tetszőleges néven, majd adj rá futtatási jogot és indítsd el.
#!/bin/sh . /etc/functions.sh config_cb() { local type="$1" local name="$2" if [ ! -z $type ] ;then echo New section - type: "$type", name: "$name" else echo "End of configuration" fi } option_cb() { local name="$1" local value="$2" echo " new option - name:" "$name", value: "$value", in section: $CONFIG_SECTION } list_cb() { local name="$1" local value="$2" echo " new list element - name:" "$name", value: "$value", in section: $CONFIG_SECTION } echo Loading system config: config_load system
Eredmény
# ./UCIcallbacktest.sh
Loading system config:
New section - type: system, name: cfg02e48a
new option - name: hostname, value: OpenWrt, in section: cfg02e48a
new option - name: timezone, value: UTC, in section: cfg02e48a
New section - type: timeserver, name: ntp
new option - name: server_ITEM1, value: 0.openwrt.pool.ntp.org, in section: ntp
new option - name: server_LENGTH, value: 1, in section: ntp
new list element - name: server, value: 0.openwrt.pool.ntp.org, in section: ntp
new option - name: server_ITEM2, value: 1.openwrt.pool.ntp.org, in section: ntp
new option - name: server_LENGTH, value: 2, in section: ntp
new list element - name: server, value: 1.openwrt.pool.ntp.org, in section: ntp
new option - name: server_ITEM3, value: 2.openwrt.pool.ntp.org, in section: ntp
new option - name: server_LENGTH, value: 3, in section: ntp
new list element - name: server, value: 2.openwrt.pool.ntp.org, in section: ntp
new option - name: server_ITEM4, value: 3.openwrt.pool.ntp.org, in section: ntp
new option - name: server_LENGTH, value: 4, in section: ntp
new list element - name: server, value: 3.openwrt.pool.ntp.org, in section: ntp
new option - name: enable_server, value: 0, in section: ntp
End of configuration |
Három dolgot kell észrevenni:
option_cb
callback. Ez valószinűleg a keretscript hibája, reméljük, hogy kijavítják valamikor.config_cb
hívás, amit a függvényen belül le kell kezelni
A másik módszer a konfigurációs fájlok feldolgozására, hogy előbb betöltjük az egész fájlt a memóriába, majd sorban végigmegyünk a section-ökön a config_foreach
procedúra használatával.
Ez inkább akkor használatos, ha a section-ök típusa adott (tudjuk, hogy milyen option-ok vannak bennük), de nem tudjuk előre, hogy hány ilyen típusú section lesz.
Sajnos option_foreach
procedúra jelenleg nincs a rendszerben.
A config_foreach
procedúrának egy kötelező és további opcionális paraméterei vannak:
Az alábbi példában a saját handle_interface
procedúra meghívódik minden egyes config interface
section-höz
a /etc/config/network
fájlban. A test
string extra paraméterként átadódik a saját procedúránknak.
#!/bin/sh . /etc/functions.sh handle_interface() { local config="$1" local custom="$2" echo New section: "$config", custom parameter: "$custom" # minden új section esetén futtatandó parancsok } config_load network config_foreach handle_interface interface test
Megszakíthatjuk az iterációt, ha nem nulla értékkel térünk vissza a függvényből (return 1
).
A section-ön belül a config_get
vagy a config_set
függvények segítségével beolvashatók vagy megváltoztathatók az option-ok értékei.