Linux
OpenWrt
OpenWrt サンプルプログラム掲載! UCIコマンド用C言語ライブラリ
- libuci
post:
update:
この記事で紹介するソースコードは自由に使っていただいて構いません。
アプリケーションの開発や自己学習にお役立て下さい。ただし、当ブログでは掲載するソースコードを流用・利用したことによる損害等につきましては
一切の責任を負いません。自己責任で利用お願いします。
今回は、OpenWrtアーキテクチャ要素の1つであるUCIコマンドのC言語コアライブラリ-libuciについて紹介します。
この記事は、開発者の方が自作アプリケーションにlibuciを使用して、UCIコマンドと同等な処理を直接プログラムに実装できる
ようになることを目指して書いたものです。言わばリファレンス的な記事になります。
一般的なリファレンスにあるような無味乾燥な説明に留まらず、都度、サンプルプログラムを掲載して丁寧な解説を書くように心掛けました。
個人的には少しニッチすぎる記事かなと思いますが、誰かの参考になれば幸いです。
それでは行ってみましょう。
目次
- サンプルプログラムのダウンロード
- ビルド時のlibuciライブラリ指定方法
- libuciリファレンス
- uci_alloc_context
- uci_free_context
- uci_lookup_ptr
- uci_perror
- uci_get_errorstr
- uci_foreach_element
- uci_set
- uci_save
- uci_add_section
- uci_load
- uci_unload
- uci_add_list
- uci_del_list
- uci_reorder_section
- uci_rename
- uci_delete
- uci_commit
- uci_list_configs
- uci_set_savedir
- uci_set_confdir
- uci_add_delta_path
- uci_revert
- uci_parse_argument
- uci_set_backend
- uci_validate_text
- uci_parse_ptr
- uci_lookup_next
- uci_parse_section
- uci_hash_options
- サンプルソフトウェアのダウンロードリスト
- 関連記事
- 参考文献
サンプルプログラムのダウンロード
このリファレンスで紹介するサンプルプログラムは私のGitHubリポジトリ上に存在します。
ダウンロードしたい方は次のgitコマンドでクローンしてください。
git clone https://github.com/utakamo/UtakamoStudyApps.git
サンプルプログラムの一覧と簡単な説明を以下に掲載します。
学習を目的としていますので、処理をする上で全く意味をなさないプログラムもあります。予めご了承ください。
お試しインストール(Raspbbery Pi限定)
ご自身の環境で実行してみるほどの物ではないかもしれませんが、Raspberry Pi限定でサンプルプログラムのパッケージを配布します。 お手持ちのRasberry Pi上で実行してみたい方は、次の手順を参考にインストールしてみて下さい。
- 手順1:お手持ちのRaspberry Pi(OpenWrt導入済み)用のパッケージを次の中から探してダウンロードしてください。
(上記の表を見て、以下のURLに記載する、uci-sampleのサフィックス「xx」をダウンロードしたいパッケージの番号に変更してください。)
Raspberry Pi1(Webブラウザ経由でダウンロードしたい人はこちら)
root@OpenWrt:~# wget https://utakamo.com/repo/openwrt/raspi1/uci/uci-samplexx_1.0-1_arm_arm1176jzf-s_vfp.ipk
Raspberry Pi2(
Webブラウザ経由でダウンロードしたい人はこちら)
root@OpenWrt:~# wget https://utakamo.com/repo/openwrt/raspi2/uci/uci-samplexx_1.0-1_arm_cortex-a7_neon-vfpv4.ipk
Raspberry Pi3(
Webブラウザ経由でダウンロードしたい人はこちら)
root@OpenWrt:~# wget https://utakamo.com/repo/openwrt/raspi3/uci/uci-samplexx_1.0-1_aarch64_cortex-a53.ipk
Raspberry Pi4(
Webブラウザ経由でダウンロードしたい人はこちら)
root@OpenWrt:~# wget https://utakamo.com/repo/openwrt/raspi4/uci/uci-samplexx_1.0-1_aarch64_cortex-a72.ipk
手順2:次のコマンドでインストールと実行ができます。(例:Raspberry Pi3のuci-sample02
root@OpenWrt:~# opkg install uci-sample02_1.0-1_aarch64_cortex-a53.ipk
root@OpenWrt:~# uci-sample02 network
手順3:確認が終わったら、次のコマンドでアンインストールができます。(例:uci-sample02
root@OpenWrt:~# opkg remove uci-sample02
ビルド時のlibuciライブラリ指定方法
前節で紹介したサンプルプログラムは当然のことながら、今回の主題であるlibuciライブラリを使用しています。
そのため、サンプルプログラムは依存ライブラリとしてlibuciを予め指定してからビルドしています。
通常、依存ライブラリの指定はbuildrootが使用するMakeファイルのTARGET_LDFLAGS(※)とDEPENDSに記載する必要があります。
今回の場合ですと、libuciのライブラリ名を表す「luci」と「libuci」を指定しています。
(例:~/UtakamoStudyApps/libuci-c/uci-sample01/Makefile 抜粋部
TARGET_LDFLAGS = -luci
DEPENDS:=+libuci
※TARGET_LDFLAGSは変数名です。詳しくはサンプルプログラムのソースコンパイル用Makeファイルと
buildroot用Makeファイルの記述箇所を見てください。
今後、読者の方ご自身でlibuciライブラリを使用したソフトウェアのMakeファイルを作成する際は上記の
記述を含めることに注意してください。また、全体的なMakeファイルの記述形式の確認は、この記事で紹介するサンプル
プログラムを参考にすると良いでしょう。
補足
buildrootが使用するMakeファイルの基本的な書き方と各記述箇所に関する詳しい説明は
「【第 6 回】OpenWrt開発入門 自作アプリのパッケージ作成とインストール」を参照してください。
libuciリファレンス
以下にlibuciライブラリの各関数仕様とそのサンプルプログラムを掲載します。
- struct uci_context * uci_alloc_context(void)
-
戻り値
- 成功:uci_context*(UCIコンテキストポインタ)
- 失敗:NULL
-
説明
UCIコンフィグレーションファイルのツリーと付帯情報を展開・割り当て、そのポインタを戻り値として取得します。
ヒープメモリ上にUCIコンテキスト(uci_context)を作成し、OpenWrtシステムが持つ任意のUCIコンフィグレーションファイルを検索する際のエントリポイントになります。
他のlibuci関数は作成されたUCIコンテキストを介して対象のコンフィグを検索・操作することができます。
-
UCIコンテキストを使用するには、以下のようにコンテキストポインタを作成する必要があります。
struct uci_context *ctx = uci_alloc_context();
-
UCIコンテキストの使用後は、uci_free_context関数によってヒープメモリ上から解放する必要があります。
uci_free_context(ctx);
- サンプルプログラム(uci-sample01)
-
UCIコンテキストを作成し、その中身の一部を表示するサンプルプログラムです。
構造体定義(struct uci_context)の詳細はこちらを参照してみてください。
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
ctx = uci_alloc_context();
printf("\n");
printf("---list of config packages---\n");
printf("next package address :%p\n", ctx->root.next);
printf("prev package address :%p\n\n", ctx->root.prev);
printf("uci runtime flags :");
switch (ctx->flags)
{
case UCI_FLAG_STRICT:
printf("UCI_FLAG_STRICT\n");
break;
case UCI_FLAG_PERROR:
printf("UCI_FLAG_PERROR\n");
break;
case UCI_FLAG_EXPORT_NAME:
printf("UCI_FLAG_EXPORT\n");
break;
case UCI_FLAG_SAVED_DELTA:
printf("UCI_FLAG_SAVE_DELTA\n");
break;
default:
printf("NO FLAG HIT! (%d)\n", ctx->flags);
break;
}
printf("config directory :%s\n", ctx->confdir);
printf("savedir directory :%s\n\n", ctx->savedir);
printf("---search path for delta files---\n");
printf("delta path next :%p\n", ctx->delta_path.next);
printf("delta path prev :%p\n\n", ctx->delta_path.prev);
printf("---private---\n");
printf("err :%d\n", ctx->err);
printf("internal :%s\n", (ctx->internal ? "true" : "false") );
printf("nested :%s\n", (ctx->nested ? "true" : "false") );
printf("buffer size :%d\n", ctx->bufsz);
printf("\n");
uci_free_context(ctx);
return 0;
}
- 実行結果例
- このサンプルプログラムは引数なしで実行可能です。OpenWrtが管理するUCIコンフィグレーションファイルのツリーと付帯情報をヒープメモリ
上に割り当て、展開していることが分かります。
root@OpenWrt:~# uci-sample01
---list of config packages---
next package address :0x7f94ba9b30
prev package address :0x7f94ba9b30
uci runtime flags :NO FLAG HIT! (9)
config directory :/etc/config
savedir directory :/tmp/.uci
---search path for delta files---
delta path next :0x7f94c48880
delta path prev :0x7f94c48880
---private---
err :0
internal :false
nested :false
buffer size :0
root@OpenWrt:~#
-
uci_alloc_contextによってヒープメモリ上に割り当てられたUCIコンテキストは、各UCIコンフィグデータ
を参照できるアドレスリストを持っています。
-
他にもUCIコンフィグのフラッシュ領域パス(/etc/config)やステージング領域パス(/tmp/.uci)も持っています。
これらの情報を元に、他のlibuci関数のuci_lookup_ptr、uci_set、uci_add_listなどで指定されたUCIコンフィグレーション
ファイルのsection、option、listなどを検索して操作することが可能です。
- void uci_free_context(struct uci_context *ctx)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
-
uci_alloc_context関数によってヒープメモリ上に割り当てられたUCIコンテキストを解放します。
uci_alloc_context関数で確保されたメモリ領域は、本関数で解放されない限り、プログラム終了後も確保されたままとなります。
そのため、呼び出しは必須です。
- サンプルプログラム
-
本関数はこの記事に掲載するサンプルプログラムで必ず使用されていますので、それらをご覧ください。
- int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_ptr *ptr |
ターゲットパッケージ(UCIコンフィグ)情報。引数strによって指定されたUCIコンフィグの情報を管理。
|
| char *str |
検索対象のUCIパラメータ。フォーマットは<config>.[<section>].[<option>]=[<value>]
|
| bool extended |
true : 拡張構文サポートあり , false : 拡張構文サポートなし
|
-
戻り値
- 成功:UCI_OK [0]
- 失敗:UCI_ERR_{MEN [1], INVAL [2], NOTFOUND, IO [4], PARSE [5], DUPLICATE [6], UNKNOWN [7], LAST [8]}
-
説明
uci_lookup_ptr関数は、UCIコンフィグレーションファイルを操作する上で重要な前処理です。
任意のUCIコンテキストに対して、引数strにより渡されたUCIパラメータをキーとして、対応するUCIコンフィグ情報を検索し、ヒットしたUCIコンフィグ情報のポインタを引数ptrとして取得します。
このとき、ptrは引数strによって渡されたUCIパラメータの解析結果(config・section・option)を保持しています。
-
本関数によって取得されたUCIコンフィグ情報を使用して、UCI操作用関数を実行することで、任意のUCIコンフィグレーションファイルの操作(変更・追記・削除)が可能になります。
また、引数extendedにtrueを指定することで、拡張構文に対応したUCIパラメータの解析も行えます。
- サンプルプログラムその1(uci-sample02)
-
uci_lookup_ptr関数によって取得されるUCIコンフィグ情報をコンソール画面に出力するサンプルプログラムを掲載します。
なお、UCIコンフィグ情報は量が多いのでサンプルプログラムを2つ(uci-sample02とuci-sample03)に分けています。
-
uci-sample02は、引数として検索対象のUCIパラメータを指定して実行します。
引数の検索対象UCIパラメータがヒットした場合、該当UCIコンフィグの属性などの情報と共にその存在を「"network" is exist」
などのように表示します。
さらに、引数(str)の文字列をUCI構文として解析した結果を表示します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
if (argc != 2) {
printf("input argument error!\n ex) uci-sample02 network.lan\n");
return 1;
}
ctx = uci_alloc_context();
if (uci_lookup_ptr(ctx, &ptr, argv[1], true) != UCI_OK) {
uci_perror(ctx, "specified args error");
uci_free_context(ctx);
return 1;
}
printf("\"%s\" is exist\n", argv[1]);
printf("argument type :");
switch (ptr.target) {
case UCI_TYPE_UNSPEC:
printf("UCI_TYPE_UNSPEC\n\n");
break;
case UCI_TYPE_DELTA:
printf("UCI_TYPE_DELTA\n\n");
break;
case UCI_TYPE_PACKAGE:
printf("UCI_TYPE_PACKAGE\n\n");
break;
case UCI_TYPE_SECTION:
printf("UCI_TYPE_SECTION\n\n");
break;
case UCI_TYPE_OPTION:
printf("UCI_TYPE_OPTION\n\n");
break;
case UCI_TYPE_PATH:
printf("UCI_TYPE_PATH\n\n");
break;
case UCI_TYPE_BACKEND:
printf("UCI_TYPE_BACKEND\n\n");
break;
case UCI_TYPE_ITEM:
printf("UCI_TYPE_UNSPEC\n\n");
break;
case UCI_TYPE_HOOK:
printf("UCI_TYPE_HOOK\n\n");
break;
}
printf("----[Input Argument Syntax Parsing Result]---\n");
printf("package :%s\n", ptr.package);
printf("sectioin :%s\n", ptr.section);
printf("option :%s\n", ptr.option);
printf("value :%s\n\n", ptr.value);
printf("---[Search Result]---\n");
printf("package address :%p\n", ptr.p);
printf("section address :%p\n", ptr.s);
printf("option address :%p\n", ptr.o);
printf("last address :%p\n\n", ptr.last);
uci_free_context(ctx);
return 0;
}
- 実行結果例
-
次の引数を与えたときの実行結果を掲載します。
- network
- network.lan
- network.lan.ipaddr
- network.lan.ipaddr=192.168.4.1
root@OpenWrt:~# uci-sample02 network
"network" is exist
argument type :UCI_TYPE_PACKAGE
----[Input Argument Syntax Parsing Result]---
package :network
sectioin :(null)
option :(null)
value :(null)
---[Search Result]---
package address :0x420880
section address :0
option address :0
last address :0x420880
root@OpenWrt:~# uci-sample02 network.lan
"network" is exist
argument type :UCI_TYPE_SECTION
----[Input Argument Syntax Parsing Result]---
package :network
sectioin :lan
option :(null)
value :(null)
---[Search Result]---
package address :0x420880
section address :0x7faae51430
option address :0
last address :0x7faae51430
root@OpenWrt:~# uci-sample02 network.lan.ipaddr
"network" is exist
argument type :UCI_TYPE_OPTION
----[Input Argument Syntax Parsing Result]---
package :network
sectioin :lan
option :ipaddr
value :(null)
---[Search Result]---
package address :0x420880
section address :0x7fb77ac430
option address :0x7fb77ac3c0
last address :0x7fb77ac3c0
root@OpenWrt:~# uci-sample02 network.lan.ipaddr=192.168.4.1
"network" is exist
argument type :UCI_TYPE_OPTION
----[Input Argument Syntax Parsing Result]---
package :network
sectioin :lan
option :ipaddr
value :192.168.4.1
---[Search Result]---
package address :0x420880
section address :0x7fbf1c7430
option address :0x7fbf1c73c0
last address :0x7fbf1c73c0
root@OpenWrt:~#
-
上記を見ると、はじめに、サンプルプログラムに与えた引数の解析結果を表示していることが分かります。
引数が「network」であれば、それがUCIコンフィグのnetworkを指していると認識され、「network.lan」であれば
UCIコンフィグのnetworkが持つlanセクションを指していると認識されます。
-
そして、上記のUCIパラメータ情報を基に、UCIコンテキストから検索した該当UCIコンフィグのヒープメモリ上の
アドレスがuci_ptr *ptrに渡されることが確認できます。
-
このように、引数として与えられたUCIパラメータを解析し、該当のUCIコンフィグ情報を収集するのが
uci_lookup_ptrの役割です。
- サンプルプログラムその2(uci-sample03)
-
uci-sample03は、引数のUCIパラメータを元に検索したUCIコンフィグの詳細情報を表示するサンプルプログラムです。
このプログラムはuci getコマンドに相当します。
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
if (argc != 2) {
printf ("input argument error!\n ex) uci-sample03 network.lan\n");
return 1;
}
ctx = uci_alloc_context();
if (uci_lookup_ptr (ctx, &ptr, argv[1], true) != UCI_OK) {
uci_perror(ctx, "specified args error");
uci_free_context(ctx);
return 1;
}
printf("\n---[Search Results]---\n");
if (ptr.p != 0) {
printf(" --package info\n");
printf(" [uci_element] e.list.next :%p\n", ptr.p->e.list.next);
printf(" [uci_element] e.list.prev :%p\n", ptr.p->e.list.prev);
printf(" [uci_element] e.name :%s\n\n", ptr.p->e.name);
printf(" [uci_list] sections.next :%p\n", ptr.p->sections.next);
printf(" [uci_list] sections.prev :%p\n\n", ptr.p->sections.prev);
printf(" [uci_context] ctx :%p\n\n", ptr.p->ctx);
printf(" has_delta :%s\n", (ptr.p->has_delta ? "true" : "false") );
printf(" path :%s\n", ptr.p->path);
printf(" uci_backend address :%p\n", ptr.p->backend);
printf(" priv :%p\n", ptr.p->priv);
printf(" n_section :%d\n\n", ptr.p->n_section);
printf(" [uci_list] delta.next :%p\n", ptr.p->delta.next);
printf(" [uci_list] delta.prev :%p\n", ptr.p->delta.prev);
printf(" [uci_list] saved_delta.next :%p\n", ptr.p->saved_delta.next);
printf(" [uci_list] saved_delta.prev :%p\n\n", ptr.p->saved_delta.prev);
}
if (ptr.s != 0) {
printf(" --section info\n");
printf(" [uci_element] e.list.next :%p\n", ptr.s->e.list.next);
printf(" [uci_element] e.list.prev :%p\n", ptr.s->e.list.prev);
printf(" [uci_element] e.name :%s\n\n", ptr.s->e.name);
printf(" [uci_list] options.next :%p\n", ptr.s->options.next);
printf(" [uci_list] options.prev :%p\n\n", ptr.s->options.prev);
printf(" package address :%p\n", ptr.p);
printf(" anonymous :%s\n", (ptr.s->anonymous ? "true" : "false"));
printf(" type :%s\n\n", ptr.s->type);
}
if (ptr.o != 0) {
printf(" --option info\n");
printf(" [uci_element] e.list.next :%p\n", ptr.o->e.list.next);
printf(" [uci_element] e.list.prev :%p\n", ptr.o->e.list.prev);
printf(" [uci_element] e.name :%s\n\n", ptr.o->e.name);
printf(" section address :%p\n", ptr.o->section);
printf(" option type :");
switch (ptr.o->type) {
case UCI_TYPE_STRING:
printf("UCI_TYPE_STRING\n");
break;
case UCI_TYPE_LIST:
printf("UCI_TYPE_LIST\n");
break;
}
if (ptr.o->type == UCI_TYPE_STRING) {
printf(" option value :%s\n\n", ptr.o->v.string);
}
if (ptr.o->type == UCI_TYPE_LIST) {
printf(" [uci_list] list next :%p\n", ptr.o->v.list.next);
printf(" [uci_list] list prev :%p\n\n", ptr.o->v.list.prev);
}
}
if (ptr.last != 0) {
printf(" --last info\n");
printf(" [uci_element] list.next :%p\n", ptr.last->list.next);
printf(" [uci_element] list.prev :%p\n", ptr.last->list.prev);
printf(" [uci_element] name :%s\n\n", ptr.last->name);
}
uci_free_context(ctx);
return 0;
}
- 実行結果例
-
大半のOpenWrtデバイスに存在するUCIパラメータ(network.lan.ipaddrとsystem.ntp.server)をサンプルプログラムの引数にしたときの実行結果を掲載します。
上記を見ると、OpenWrtに存在する指定UCIパラメータの詳細情報が表示されていることが分かります。
ざっと見ただけでも、セクションのタイプや匿名性、格納されているオプション値が存在するのが分かります。
もちろん、関連するパラメーターのアドレス参照もできるようにリストデータも持っています。
-
これらのUCIコンフィグ情報を使用して、他のlibuci関数でUCI操作が可能になります。
- void uci_perror(struct uci_context *ctx, const char *str)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
UCIコンテキストは直前に実行したlibuci関数のステータスを持つ。
|
| const char *prefix |
メッセージプレフィックス。
ステータスに応じたメッセージの前に配置される文字列。
|
-
説明
本関数は、直前のlibuci関数実行によって発生したステータスに応じて、その対応メッセージをコンソールに出力します。
この関数は、UCI処理で発生したエラーに対するメッセージを表示するために使用します。
ステータスコードと対応するメッセージは以下の表に示されています。
なお、本関数は、後述のuci_get_errorstr関数のラッパーになります。
内部では、uci_get_errorstr(ctx, NULL, str)を呼び出しています。
-
| ステータスコード |
対応メッセージ |
| UCI_OK |
Success |
| UCI_ERR_MEM |
Out of memory |
| UCI_ERR_INVAL |
Invalid argument |
| UCI_ERR_NOTFOUND |
Entry not found |
| UCI_ERR_IO |
I/O error |
| UCI_ERR_PARSE |
Parse error |
| UCI_ERR_DUPLICATE |
Duplicate entry |
| UCI_ERR_UNKNOWN |
Unknown error |
- コード例
-
本関数はこの記事で紹介する多くのサンプルプログラムで使用しています。呼び出し部の
抜粋は次の通りです。
-
if (uci_lookup_ptr(ctx, &ptr, argv[1], true) != UCI_OK) {
uci_perror(ctx, "Message");
uci_free_context(ctx);
return 1;
}
-
上記のコードはuci_lookup_ptrによるUCIパラメータ検索において、エラー時のメッセージをuci_perrorによって
出力する処理です。
-
uci_lookup_ptrが正常終了(UCI_OK)の場合はエラーメッセージを出力せず、異常終了(UCI_ERR_XXX)の場合は
対応するメッセージを出力します。
次はuci_lookup_ptrの引数に存在しないUCIパラメータを与えて実行したときのメッセージ出力例です。
-
Message: Entry not found
-
今回は、検索がヒットしなかったので異常終了のUCI_ERR_NOTFOUNDがUCIコンテキストに記録されました。
-
uci_perrorは第1引数のUCIコンテキストが持つエラー情報を基に、第2引数のメッセージプレフィックス(今回の場合は"Message")と合わせ
て対応メッセージ"Entry not found"を出力します。
- void uci_get_errorstr(struct uci_context *ctx, char **dest, const char *prefix)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
UCIコンテキストは直前に実行したlibuci関数のステータスを持つ。
|
| char **dest |
ステータスコードに対応したメッセージの出力先変数を指定。
|
| const char *str |
メッセージプレフィックス。
ステータスに応じたメッセージの前に配置される文字列。
|
-
説明
本関数は、libuci関数が返すステータスコードに対応するエラーメッセージを取得するために使用されます。
uci_get_errorstr関数は、指定されたUCIコンテキストの直近のlibuci関数のステータスコードに対応するエラーメッセージを、引数に渡されたメッセージプレフィックスと組み合わせて出力先変数に返します。
-
uci_get_errorstr関数の第二引数には、エラーメッセージが格納されるバッファへのポインタを渡します。
このバッファは呼び出し側で確保する必要があります。
バッファを動的に確保する場合、確保したメモリを開放するために後でfree関数を呼び出す必要があります。
-
メッセージプレフィックスには、ステータスコードに対応したエラーメッセージの前に付与する文字列を指定します。
もし、メッセージプレフィックスを指定しなかった場合、uci_perror関数と同等の動作をします。
-
uci_get_errorstr関数は、外部へメッセージを渡す必要がある場合に直接します。
- コード例
-
次はエラー(UCI_ERR_XXX)時にLuaスクリプトとC言語バイナリのデータ交換用領域
であるLuaスタックにエラーメッセージを渡す処理です。※Luaとの連携をするにはluaライブラリが必要です。
-
lua_State* L = luaL_newstate();
if (uci_lookup_ptr(ctx, &ptr, argv[1], true) != UCI_OK) {
char *str = NULL;
uci_get_errorstr(ctx, &str, "Message");
if (str) {
lua_pushstring(L, str);
free(str);
}
}
-
上記はUCIコマンドの実装を参考にして書いたコードです。
エラーが発生した場合、uci_get_errorstr関数を使ってエラーメッセージを取得し、そのメッセージをLuaスタックに追加します。
取得したメッセージは、ヒープメモリ上に存在するため、使用後はfree関数で解放する必要があります。
- #define uci_foreach_element(_list, _ptr)
-
説明
第1引数のUCIパラメータ(config(package)・section・option・list)情報が持つ参照リストから
同じ区分の隣接パラメータ情報を取得します。uci_foreach_elementはイテレータマクロであり、ループ毎
に上記の取得処理を実行します。
-
そのため、uci_foreach_elementのループ中に、取得UCIパラメータ情報を利用した処理を記述することが
できます。
-
終了条件は開始地点となったUCIパラメータに参照が戻ってきたときです。
このことは個々のUCIパラメータが持つ参照リスト(uci_list)が円環状(リングバッファ)であることを示唆しています。
- サンプルプログラム(uci-sample04)
-
次はuci_foreach_elementを利用して、uci showコマンドと同等な処理をするサンプルプログラムです(※)。
任意のUCIセクションが持つオプションとその値を全て表示します。
また、特定のオプションやリストが指定された場合は、その値を表示します。
-
※ただし、サンプルプログラムのため、対応する引数の形式は次の2つのみです。
- uci-sample04 <config>.<section>
- uci-sample04 <config>.<section>.<option>
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
void show_option_value(struct uci_ptr ptr);
void show_list_value(struct uci_option *);
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
ctx = uci_alloc_context();
if (argc != 2) {
printf ("input argument error! specify uci parameter.\n ex) uci-sample04 network.lan\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.o != NULL && ptr.option != NULL) {
if (ptr.o->type == UCI_TYPE_STRING) {
printf("%s.%s.%s=%s\n", ptr.p->e.name, ptr.s->e.name, ptr.o->e.name, ptr.o->v.string);
}
else if (ptr.o->type == UCI_TYPE_LIST) {
printf("%s.%s.%s=", ptr.p->e.name, ptr.s->e.name, ptr.o->e.name);
show_list_value(uci_to_option(&ptr.o->e));
}
}
else if (ptr.o == NULL && ptr.option != NULL)
printf("not found\n");
else if (ptr.s != NULL && ptr.option == NULL)
show_option_value(ptr);
else
printf ("specify up to a section.\n");
uci_free_context(ctx);
return 0;
}
void show_option_value(struct uci_ptr ptr) {
struct uci_element *e;
uci_foreach_element(&ptr.s->options, e) {
struct uci_option *o = uci_to_option(e);
if (o->type == UCI_TYPE_STRING) {
printf("%s.%s.%s=%s\n", ptr.p->e.name, ptr.s->e.name, o->e.name, o->v.string);
}
else if (o->type == UCI_TYPE_LIST) {
printf("%s.%s.%s=", ptr.p->e.name, ptr.s->e.name, o->e.name);
show_list_value(o);
}
}
}
void show_list_value(struct uci_option *o) {
struct uci_element *e;
uci_foreach_element(&o->v.list, e) {
printf("\"%s\" ", e->name);
}
printf("\n");
}
- 実行結果
- 実行してみると、次のようにオプションを一覧表示させていることが分かります。
root@OpenWrt:~# uci-sample04 network.lan
network.lan.device=phy0-ap0
network.lan.proto=static
network.lan.ipaddr=192.168.4.1
network.lan.netmask=255.255.255.0
network.lan.ip6assign=60
root@OpenWrt:~# uci-sample04 system.ntp.server
system.ntp.server="0.openwrt.pool.ntp.org" "1.openwrt.pool.ntp.org" "2.openwrt.pool.ntp.org" "3.openwrt.pool.ntp.org"
root@OpenWrt:~#
- int uci_set(struct uci_context *ctx, struct uci_ptr *ptr)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_ptr *ptr |
処理対象のUCIコンフィグと入力UCIパラメータの解析結果情報を示すポインタ。通常、uci_lookup_ptrによって取得されるUCIコンフィグ情報。
|
-
戻り値
-
説明
本関数は名前付きセクションとオプションを作成または変更する処理です。uci_set関数はuci setコマンドの実装に使用されています。
入力UCIパラメータの解析結果(ptr)を基に、必要に応じてセクションやオプションのデータを作成します。
-
通常、uci_set関数に続けてuci_save関数を実行することで、ステージング領域(デフォルト:/tmp/.uci)に変更内容が保存されます。
- サンプルプログラム(uci-sample05)
-
uci_set関数を使用して、uci setコマンドと同等な処理をするサンプルプログラムを掲載します。
本家のuci setコマンドと同様に名前付きセクションとオプションの作成が可能です。※匿名セクションはuci_add_section関数により作成可能です。
-
- uci-sample05 <config>.<section>=<section-type>
- uci-sample05 <config>.<section>.<option>=<value>
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
void show_option_value(struct uci_ptr ptr);
void show_list_value(struct uci_option *);
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc != 2) {
printf("input argument error! specify uci parameter.\n");
printf("ex1) uci-sample05 <config>.<section>=<section-type>\n");
printf("ex2) uci-sample05 <config>.<section>.<option>=<value>\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.value)
ret = uci_set(ctx, &ptr);
else {
printf("Parser error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
return 0;
}
- 実行結果
-
次は、UCIコンフィグレーションファイルとして空のtestファイルを/etc/configに作成し、サンプルプログラム(uci-sample05)によって名前付きセクションと
オプションを設定してみた結果です。
root@OpenWrt:~# touch /etc/config/test
root@OpenWrt:~# uci-sample05 test.section=sample
root@OpenWrt:~# uci-sample05 test.section.data=hello
root@OpenWrt:~# uci show test
test.section=sample
test.section.data='hello'
root@OpenWrt:~# uci changes
test.section='sample'
test.section.data='hello'
root@OpenWrt:~#
-
タイプ属性がsampleで名前が"section"のセクションデータと、その配下に"hello"という文字列を持ったdataオプションが作成できた
ことが分かります。本家のuci showコマンドやchangesコマンドで正しくUCIシステムによって管理されていることも確認出来ます。
- int uci_save(struct uci_context *ctx, struct uci_package *p)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_package *p |
処理対象のUCIコンフィグ情報ポインタ。
|
-
戻り値
-
本関数は指定UCIコンフィグレーションファイル(uci_package *p)の変更差分をステージング領域に保存します。
ここで言う、変更差分とはuci_setやuci_add_section関数
によって変更・追加・削除されたセクションやオプション情報のことを指します。
-
補足
ステージング領域はデフォルトで/tmp/.uciが設定されています。ステージング領域はuci_set_savedirにより変更可能です。
- サンプルプログラム
-
UCIパラメータを操作する他のサンプルプログラム中で使用されています。そちらを参考にしてみてください。
- int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_package *p |
処理対象のUCIコンフィグ情報ポインタ。
|
| const char *type |
セクションに与えるタイプ情報。
|
| struct uci_section **res |
本関数により、作成した匿名セクションポインタ。
|
-
戻り値
-
説明
uci_add_section関数は匿名セクションを作成するための処理です。本関数はuci addコマンドの実装で使用されています。
第2引数のpは処理対象のUCIコンフィグ情報ポインタであり、通常はuci_load関数によって取得します。
第3引数のtypeが示す文字列をタイプ情報として、匿名セクションを作成します。作成された匿名セクションのポインタアドレスは第4引数のresから取得することが出来ます。
-
uci_save関数を使用して、変更内容をステージング領域(デフォルト:/tmp/.uci)に保存することができます。
- サンプルプログラム(uci-sample06)
-
uci addコマンドと同等な処理をするサンプルプログラムを掲載します。uci_load関数により、対象UCIコンフィグ情報を取得し、
uci_add_section関数によって匿名セクションの追加をしています。最後に、uci_save関数でステージング領域に追加した匿名セクションを
記録することで結果としてuci addコマンドと同等な処理を実現しています。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx = NULL;
struct uci_package *p = NULL;
struct uci_section *s = NULL;
int ret = UCI_OK;
if (argc != 3) {
printf("ex) uci-sample06 <config> <section-type>");
return 1;
}
ctx = uci_alloc_context();
if ((ret = uci_load(ctx, argv[1], &p)) != UCI_OK)
{
uci_free_context(ctx);
return 1;
}
if ((ret = uci_add_section(ctx, p, argv[2], &s)) != UCI_OK)
{
uci_free_context(ctx);
return 1;
}
if (ret == UCI_OK)
{
uci_save(ctx, p);
printf("unamed section :%s\n", s->e.name);
}
uci_free_context(ctx);
return 0;
}
-
補足
このサンプルプログラムは、コマンドライン引数として、対象のUCIコンフィグファイル名と新しく追加するセクションのタイプを指定します。
その後、指定されたUCIコンフィグファイルをuci_load関数で読み込み、uci_add_section関数を使用して新しい匿名セクションを追加します。
追加が成功した場合は、uci_save関数を使用して変更内容をステージング領域に保存し、作成された匿名セクションの名前を表示します。
最後に、uci_free_context関数を使用してUCIコンテキストを解放します。
- 実行結果
-
次は、テスト用に作成したUCIコンフィグレーションファイルのtestにutakamoタイプの匿名セクションを追加した例です。
root@OpenWrt:~# touch /etc/config/test
root@OpenWrt:~# uci-sample06 test utakamo
unamed section :cfg016b17
root@OpenWrt:~# uci changes
test.cfg016b17='utakamo'
root@OpenWrt:~#
-
実行結果を見ると、uci-sample06プログラムがtestファイルを読み込み、そこにutakamoというタイプの
匿名セクションを追加しています。実行結果の最後に表示されるunamed sectionの後ろに続く文字列は、
追加された匿名セクションの名前(例えば、cfg016b17)を表しています。そして、uci changesコマンド
を実行することで、ステージング領域に追加内容が記録されていることが確認できます。
- int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| const char *name |
ロード対象のUCIコンフィグ名。
|
| struct uci_package **package |
ロードしたUCIコンフィグポインタ。
|
-
戻り値
- 成功:0
- 失敗:UCI_ERR_{MEN [1], NOTFOUND, IO [4], PARSE [5], UNKNOWN [7]}
-
説明
本関数は指定されたUCIコンフィグをロードし、その情報をUCIコンテキストに格納するための処理です。
第2引数のnameには、ロードしたいUCIコンフィグの名前を指定します。
-
第3引数のpackageは、ロードしたUCIコンフィグ情報を含む構造体へのポインタのポインタを指定します。本関数が成功した場合、0が返されます。
失敗した場合は、それに応じたエラーコードが返されます。
-
uci_load関数は、任意のUCIコンフィグに対して操作を行う前に必要なロード処理です。
これにより、UCIコンテキストに必要な情報が読み込まれ、以降の操作で利用することができます。
- サンプルプログラム
-
uci_loadはuci-sample06などで使用しています。そちらを確認して見て下さい。
- int uci_unload(struct uci_context *ctx, struct uci_package *p)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_package *p |
アンロードするUCIコンフィグ情報ポインタ。
|
-
戻り値
-
説明
本関数はUCIコンテキストにロードされたUCIコンフィグ情報を解放するために使用します。
UCIコンフィグ情報は、uci_load関数でUCIコンテキストにロードされ、uci_unload関数でアンロードされるまで、UCIコンテキスト内で保持され続けます。
複数のUCIコンフィグ情報がUCIコンテキストにロードされている場合、uci_unload関数は、
引数で指定されたUCIコンフィグ情報のみを解放し、その他のUCIコンフィグ情報は保持したままになります。
- サンプルプログラム
-
uci_unload関数は、この記事に掲載するサンプルプログラムで使用されていますので、そちらをご覧ください。
- int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_package *p |
処理対象のUCIコンフィグ情報ポインタ。
|
-
戻り値
-
説明
任意のUCIコンフィグのリストデータを作成・追加します。
- サンプルプログラム(uci-sample07)
-
uci add_listコマンドと同等な処理をするサンプルプログラムを掲載します。
uci_lookup_ptr関数により、操作対象のUCIコンフィグ情報を引き当てた上でuci_add_listで
リストデータを作成します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc != 2) {
printf("input argument error! specify uci parameter.\n");
printf("ex) uci-sample07 <config>.<section>.<option>=<value>\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.value)
ret = uci_add_list(ctx, &ptr);
else {
printf("Parser error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
return 0;
}
- 実行結果
-
引数としてリストデータを与えて実行すると、そのデータ値を対象リストに追加します。
また、リストデータが存在しない場合は作成します。
root@OpenWrt:~# touch /etc/config/test
root@OpenWrt:~# uci set test.section=utakamo
root@OpenWrt:~# uci-sample07 test.section.list=1
root@OpenWrt:~# uci-sample07 test.section.list=2
root@OpenWrt:~# uci-sample07 test.section.list=3
root@OpenWrt:~# uci-sample07 test.section.list=4
root@OpenWrt:~# uci-sample07 test.section.list=5
root@OpenWrt:~# uci changes
test.cfg016b17='utakamo'
test.section='utakamo'
test.section.list+='1'
test.section.list+='2'
test.section.list+='3'
test.section.list+='4'
test.section.list+='5'
root@OpenWrt:~#
- int uci_del_list(struct uci_context *ctx, struct uci_ptr *ptr)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_package *p |
処理対象のUCIコンフィグ情報ポインタ。
|
-
戻り値
-
説明
任意のUCIコンフィグのリストデータを削除します。
- サンプルプログラム(uci-sample08)
-
uci del_listコマンドと同等な処理をするサンプルプログラムを掲載します。
uci_lookup_ptr関数により、操作対象のUCIコンフィグ情報を引き当てた上でuci_del_listで
リストデータを削除します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc != 2) {
printf("[uci_del_list]\n");
printf("input argument error! specify uci parameter.\n");
printf("ex) uci-sample08 <config>.<section>.<option>=<value>\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.value)
ret = uci_del_list(ctx, &ptr);
else {
printf("Parser error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
return 0;
}
- 実行結果
-
引数としてリストデータの値(今回の場合では'3')を与えて実行すると、そのデータ値を対象リストから
削除します。
-
- int uci_reorder_section(struct uci_context *ctx, struct uci_section *s, int pos)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_section *s |
処理対象のUCIセクション情報ポインタ。
|
| int pos |
移動先のセクション位置
|
-
戻り値
-
説明
任意のUCIコンフィグのセクションを第3引数で示す位置に移動します。
セクションの位置はUCIコンフィグレーションファイルの先頭から順に数えられます。
一番先頭のセクション位置は0です。
- サンプルプログラム(uci-sample09)
-
uci reorderコマンドと同等な処理をするサンプルプログラムを掲載します。
uci_lookup_ptr関数によって、操作対象のUCIコンフィグ情報を引き当てた上でuci_reorder_section
により特定セクションを指定位置に移動させます。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc != 2) {
printf("[uci_reorder_section]\n");
printf("input argument error! specify uci parameter.\n");
printf("ex) uci-sample09 <config>.<section>=<pos>\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.value)
uci_reorder_section(ctx, ptr.s, strtoul(ptr.value, NULL, 10));
else {
printf("Parser error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
return 0;
}
- 実行結果
-
次は、testコンフィグの先頭に配置された「sectionA」セクションを末尾に移動してみた例です。
このtestコンフィグはセクションを3つ持ち、末尾のセクション位置は2です。そのため、引数を
「test.sectionA=2」としてサンプルプログラムを実行することでsectionAを末尾に移動出来ます。
-
- int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_ptr *ptr |
処理対象のUCIコンフィグ情報ポインタ。
|
-
戻り値
-
説明
任意のUCIコンフィグのセクション名を変更します。
- サンプルプログラム(uci-sample10)
-
uci renameコマンドと同等な処理をするサンプルプログラムを掲載します。
uci_lookup_ptr関数によって、操作対象のUCIコンフィグ情報を引き当てた上でuci_rename
により特定セクションの名前を変更します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc != 2) {
printf("[uci_rename]\n");
printf("input argument error! specify uci parameter.\n");
printf("ex) uci-sample10 <config>.<section>=<new sesction name>\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.value)
ret = uci_rename(ctx, &ptr);
else {
printf("Parser error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
return 0;
}
- 実行結果
-
特定セクションと新しい名前を引数にして実行すると、セクション名が変更できることが分かります。
次は「section」セクションを「sec」セクションに変更しています。
-
- int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_ptr *ptr |
処理対象のUCIコンフィグ情報ポインタ。
|
-
戻り値
-
説明
任意のUCIコンフィグのセクション・オプションを削除します。
- サンプルプログラム(uci-sample11)
-
uci deleteコマンドと同等な処理をするサンプルプログラムを掲載します。
uci_lookup_ptr関数によって、操作対象のUCIコンフィグ情報を引き当てた上でuci_delete
により特定セクション・オプションを削除します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc != 2) {
printf("[uci_delete]\n");
printf("input argument error! specify uci parameter.\n");
printf("ex) uci-sample11 <config>.<section>.<option>\n");
return 1;
}
uci_lookup_ptr(ctx, &ptr, argv[1], true);
if (ptr.value)
ret = uci_delete(ctx, &ptr);
else {
printf("Parser error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
return 0;
}
- 実行結果
-
任意のセクションやオプションを引数にして実行すると、該当データが削除できることが確認できます。
-
- int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overwrite)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_package **package |
処理対象のUCIコンフィグリストのポインタ。
|
| bool overwrite |
ステージング領域の消去フラグ。true:コミット時に消去、false:消去しない。
|
-
戻り値
-
説明
ステージング領域(デフォルトでは/tmp/.uci)に存在する変更差分をFLASH領域(デフォルトでは/etc/config)
の対応するUCIコンフィグレーションファイルにコピー(マージ)します。
- サンプルプログラム(uci-sample12)
-
uci commitコマンドと同等な処理をするサンプルプログラムを掲載します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
void commit_one_package(struct uci_context*, char*);
void commit_all_package(struct uci_context*);
int main(int argc, char **argv)
{
struct uci_context *ctx;
int ret = UCI_OK;
ctx = uci_alloc_context();
if (argc == 2) {
commit_one_package(ctx, argv[1]);
}
else {
commit_all_package(ctx);
}
uci_free_context(ctx);
return 0;
}
void commit_one_package(struct uci_context *ctx, char* arg) {
struct uci_ptr ptr;
if (uci_lookup_ptr(ctx, &ptr, arg, true) != UCI_OK) {
uci_perror(ctx, "Message");
return;
}
if (ptr.p != 0) {
if (uci_commit (ctx, &ptr.p, true) != UCI_OK) {
uci_perror(ctx, "Message");
return;
}
}
}
void commit_all_package(struct uci_context *ctx) {
struct uci_ptr ptr;
char **configs = NULL;
char **p;
if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs) {
uci_perror(ctx, "Message");
return;
}
for (p = configs; *p; p++) {
if (uci_lookup_ptr (ctx, &ptr, *p, true) != UCI_OK) {
uci_perror(ctx, "Message");
break;
}
if (uci_commit(ctx, &ptr.p, false) != UCI_OK) {
uci_perror(ctx, "Message");
break;
}
if (ptr.p)
uci_unload(ctx, ptr.p);
}
free(configs);
}
- 実行結果
-
- int uci_list_configs(struct uci_context *ctx, char ***list)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| char ***list |
UCIコンフィグのリストポインタ。
|
-
説明
本関数は利用可能なすべてのUCIコンフィグ名を取得するために使用します。
つまり、UCIコンフィグレーションファイル全体に対して操作を行いたい場合のUCIコンフィグファイル情報の取得処理です。
例えば、コンフィグファイル内のすべてのセクションやオプションを一覧表示したい場合などに使用できます。
- サンプルプログラム
-
uci-sample12などで使用していますので、使い方はそちらをご覧ください。
- int uci_set_savedir(struct uci_context *ctx, const char *dir)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| const char *dir |
変更先ディレクトリパス。
|
-
説明
本関数は、ステージング領域(デフォルトでは/tmp/.uci)のディレクトリ先を変更します。
ステージング領域にデータをコピーするuci_save関数を実行する前に、uci_set_savedir関数でディレクトリを
変更する必要があります。
- コード例
-
以下はuci_set_savedir関数の使用方法を示したコードです。
-
struct uci_context *ctx = uci_alloc_context();
if (uci_lookup_ptr(ctx, &ptr, arg, true) != UCI_OK) {
uci_perror(ctx, "Message");
return;
}
/* UCI操作関数 例:uci_setなど */
uci_set_savedir(ctx, "/etc/config");
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context(ctx);
- int uci_add_delta_path(struct uci_context *ctx, const char *dir)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| const char *dir |
変更先ディレクトリパス。
|
-
戻り値
- 成功:0
- 失敗:0以外(例:同一ディレクトリ追加時はUCI_ERR_DUPLICATE)
-
説明
本関数は、変更差分(delta)を検索するディレクトリパスを追加します。
追加したディレクトリは、コミットしないオーバーレイ差分の参照先として扱われます。
すでに同じディレクトリが登録済みの場合はエラーになります。
- int uci_set_confdir(struct uci_context *ctx, const char *dir)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| const char *dir |
変更先ディレクトリパス。
|
-
説明
本関数は、uci_commit関数によるステージングデータのコピー・マージ先ディレクトリを変更します。
デフォルトのディレクトリは通常、/etc/configです。そのディレクトリを変更するのがuci_set_confdir関数です。
- コード例
-
uci_set_confdir関数を使用するコードの抜粋です。通常、uci_commit関数の前に実行します。
-
struct uci_context *ctx = uci_alloc_context();
if (uci_lookup_ptr (ctx, &ptr, arg, true) != UCI_OK) {
uci_perror(ctx, "Message");
return;
}
/* UCI操作関数 例:uci_set関数など*/
uci_set_confdir(ctx, "/etc/config");
if (uci_commit(ctx, &ptr.p, false) != UCI_OK) {
uci_perror (ctx, "Message");
break;
}
uci_free_context(ctx);
- int uci_revert(struct uci_context *ctx, struct uci_ptr *ptr)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| uci_ptr *ptr |
処理対象のUCIコンフィグ情報ポインタ。
|
-
戻り値
-
説明
ステージング領域(デフォルトでは/tmp/.uci)に存在する変更差分を消去します。
- サンプルプログラム(uci-sample13)
-
uci revertコマンドと同等な処理をするサンプルプログラムを掲載します。
引数としてUCIコンフィグレーションファイル名を与えられた場合は、そのファイル名に対応するステージング領域の変更差分を
全て消去します。また、引数として特定セクションを与えた場合は、そのセクションの変更差分を消去します。
-
#include <stdio.h>
#include <string.h>
#include <uci.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
struct uci_context *ctx;
struct uci_ptr ptr;
int ret = UCI_OK;
ctx = uci_alloc_context ();
if (argc != 2) {
printf ("[uci_revert]\n");
printf ("input argument error! specify uci parameter.\n");
printf ("ex) uci-sample13 <config>.[<section>]\n");
return 1;
}
uci_lookup_ptr (ctx, &ptr, argv[1], true);
if (ptr.p != 0)
ret = uci_revert (ctx, &ptr);
else {
printf ("Parse error\n");
ret = UCI_ERR_PARSE;
}
if (ret == UCI_OK)
uci_save(ctx, ptr.p);
uci_free_context (ctx);
return 0;
}
- 実行結果
-
- int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| FILE *stream |
ファイルストリーム。
|
| char **str |
文字列リストポインタ。
|
| char **result |
文字列リストポインタ。
|
-
説明
本関数は、シェル引数を解析するために使用します。
主にファイルや標準入力ストリームからシェル引数を受け取りたいときに使用します。
- int uci_set_backend(struct uci_context *ctx, const char *name)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| const char *name |
使用するバックエンド名。通常はfileを指定。
|
-
説明
本関数は、UCIコンテキストが使用するバックエンドを切り替えます。
標準のバックエンドはfileで、/etc/configを設定保存先として扱います。
通常のOpenWrt運用では明示的に切り替える機会は多くありません。
- bool uci_validate_text(const char *str)
-
| <型> <引数名> |
説明 |
| const char *str |
バリデーション対象の文字列
|
-
戻り値
- 成功:true(UCIパラメータとして有効な文字列です。)
- 失敗:false(UCIパラメータとして不正な文字列です。)
-
説明
本関数は、引数のUCIパラメータ文字列が正当な形式であるかチェックします。uci_validate_textは
他の操作関数(uci_set、uci_add_section、uci_add_listなど)の内部で使用されます。そのため、
開発者はuci_validate_text関数を意識する必要はありません。
- int uci_parse_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_ptr *ptr |
処理対象のUCIコンフィグ情報ポインタ。
|
| char *str |
解析対象のUCIパラメータ文字列(例:network.lan.ipaddr)。
本関数内部で文字列内容が書き換えられます。
|
-
説明
本関数は、第2引数で示されるUCIコンフィグ情報から操作対象のコンフィグファイル、セクション、パラメータを
解析するための処理です。主にuci_set関数などの操作関数の内部で実行される処理であり、開発者はuci_parse_ptr
を意識する必要はありません。
- int uci_lookup_next(struct uci_context *ctx, struct uci_element **e, struct uci_list *list, const char *name)
-
| <型> <引数名> |
説明 |
| struct uci_context *ctx |
UCIコンテキスポインタ。
通常、uci_alloc_contextでヒープメモリに割り当てたUCIコンテキストのアドレスを指定。
|
| struct uci_element **e |
検索結果を書き込む要素ポインタの参照。
|
| struct uci_list *list |
検索対象の要素リスト。
|
| const char *name |
検索する子要素名。
|
-
説明
本関数は、指定した要素リストからnameに一致する子要素を検索して
第2引数eに返します。主にuci_lookup_ptrなどの内部処理で使われる補助関数です。
- void uci_parse_section(struct uci_section *s, const struct uci_parse_option *opts, int n_opts, struct uci_option **tb)
-
| <型> <引数名> |
説明 |
| struct uci_section *s |
解析対象のセクション。
|
| const struct uci_parse_option *opts |
検索するオプション定義の配列。
|
| int n_opts |
opts配列の要素数。
|
| struct uci_option **tb |
検出したオプションを格納する出力配列。
見つからない要素はNULLになります。
|
-
説明
本関数は、対象セクションからoptsで指定した複数オプションをまとめて検索し、
結果をtbへ格納します。複数オプションを一括で引き当てるための内部向け関数です。
- uint32_t uci_hash_options(struct uci_option **tb, int n_opts)
-
| <型> <引数名> |
説明 |
| struct uci_option **tb |
ハッシュ計算対象のオプションポインタ配列。
|
| int n_opts |
tb配列の要素数。
|
-
説明
本関数は、オプション配列の内容からハッシュ値を計算します。
設定変更の検知や比較処理のために内部で利用される関数です。
サンプルソフトウェアのダウンロードリスト
Webブラウザを通してサンプルソフトウェアをダウンロードするためのリンクを貼ります。
ダウンロードしたらOpenWrtデバイスにftpやscpを利用してアップロードしてみてください。
Raspberry Pi1用パッケージ
| パッケージ |
ハッシュ(SHA256) |
ダウンロード |
| uci-sample01_1.0-1_arm_arm1176jzf-s_vfp.ipk |
5499df5f93e10d24285ff48bc2418a30dd9e3ac10ead68f335cd66d140d15c75 |
DOWNLOAD |
| uci-sample02_1.0-1_arm_arm1176jzf-s_vfp.ipk |
f737404442f341a94109f9de930ae6a5bb758be74a479cb5ab76a035a67f1dd5 |
DOWNLOAD |
| uci-sample03_1.0-1_arm_arm1176jzf-s_vfp.ipk |
b2bc6b620c553f7caf715b69ee6567136f5ff71356e909dba46d2f80a8f990cc |
DOWNLOAD |
| uci-sample04_1.0-1_arm_arm1176jzf-s_vfp.ipk |
863d4956b1a9e63d5b823e0fa169c05c1b691a73e3b24f51b36db4d55039eddf |
DOWNLOAD |
| uci-sample05_1.0-1_arm_arm1176jzf-s_vfp.ipk |
6b215f8c25df41055d70f09c63b0083ec91b4084fea55434ac182dbb629d7748 |
DOWNLOAD |
| uci-sample06_1.0-1_arm_arm1176jzf-s_vfp.ipk |
2991862210dfd6fa382e11a5d7c1212eb34011be5fd57d15f9dd92a67809ad90 |
DOWNLOAD |
| uci-sample07_1.0-1_arm_arm1176jzf-s_vfp.ipk |
f7768a9a51825bde8a511af91102a95e94d82647f1c8058ef4390e5cf7ef7f72 |
DOWNLOAD |
| uci-sample08_1.0-1_arm_arm1176jzf-s_vfp.ipk |
a0e0e84c7e9e019293bfad3ba6b76e268ae7e1ef045300eef73799c38c830c98 |
DOWNLOAD |
| uci-sample09_1.0-1_arm_arm1176jzf-s_vfp.ipk |
d3706b628fe534aa44057241861ea8af2aa7e9dcc5851b072368a9e06e5de2ce |
DOWNLOAD |
| uci-sample10_1.0-1_arm_arm1176jzf-s_vfp.ipk |
1f28ccb68cea364983d94e5d28e8a89383e612a3eefedf10c31a79cfb8c434a4 |
DOWNLOAD |
| uci-sample11_1.0-1_arm_arm1176jzf-s_vfp.ipk |
fd562a6fc20bce5a9ae22a15c618335854961af7a2be6d3dd8ea11a15d023a59 |
DOWNLOAD |
| uci-sample12_1.0-1_arm_arm1176jzf-s_vfp.ipk |
d3df2c76d0fe2a792743016444e21f32fb654ff15034c219adaa537fac3e7c23 |
DOWNLOAD |
Raspberry Pi2用パッケージ
| パッケージ |
ハッシュ(SHA256) |
ダウンロード |
| uci-sample01_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
2c127081cc5a3fea494b21e18974fb71a78f54bc19df75b41b64a5a660fab0e4 |
DOWNLOAD |
| uci-sample02_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
1577b03f92068a42418551c171164ac99e94282255d49dee0600239554eeac68 |
DOWNLOAD |
| uci-sample03_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
b506619668d5996171b0c379f9324aec1443787d0a9fb3ad4fee6175d20168e6 |
DOWNLOAD |
| uci-sample04_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
09b44812dd7cdcc344356208b2e3ff499122c2dc13c2279bc0b37db3ce407af5 |
DOWNLOAD |
| uci-sample05_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
e75f1cb0052c17397e123d9482b50a76a154d683871d8b25fcbc54d1610edf88 |
DOWNLOAD |
| uci-sample06_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
430fadf1b88b06f307a1fbea5c544e0ba03dcd1c94474cc08fd86e4ace947ef5 |
DOWNLOAD |
| uci-sample07_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
b27a5c15c5e15c7da418717d73a6eda7ba27b86eb527050b684077e3154f1bc3 |
DOWNLOAD |
| uci-sample08_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
c48e9d961d5017ec8624bb436a03c3db3049e1417ae16735b5a69df1b984cacf |
DOWNLOAD |
| uci-sample09_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
4e4f34f559ae8d794d9af5f9703b79006f3278c58324b267c7cc89be2d5b075b |
DOWNLOAD |
| uci-sample10_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
cd5cd3850e506514c25661499f4b0d2ce70c3c541e059d185ab24a6be355325e |
DOWNLOAD |
| uci-sample11_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
99ec6a7246b56db84b3258a696b57a992754efc4317adb40ccc044dc919d3b0c |
DOWNLOAD |
| uci-sample12_1.0-1_arm_cortex-a7_neon-vfpv4.ipk |
daecefc304b709137cdde933c7e8a28839593fe94a31c4d18da434cb963baf64 |
DOWNLOAD |
Raspberry P3用パッケージ
| パッケージ |
ハッシュ(SHA256) |
ダウンロード |
| uci-sample01_1.0-1_aarch64_cortex-a53.ipk |
b8c4d411a89c4c3981b9fd55f26325f6313ccc8add940eba84db2c6cd41f2d42 |
DOWNLOAD |
| uci-sample02_1.0-1_aarch64_cortex-a53.ipk |
ac93dee897f5dd43bcb317aa9804299e69325c5678d9520b9df28abe7bf48e52 |
DOWNLOAD |
| uci-sample03_1.0-1_aarch64_cortex-a53.ipk |
0d3a0cfff6d6a7705130d44fc758efc1826d222e83d94fc69afb9e2b2673dc60 |
DOWNLOAD |
| uci-sample04_1.0-1_aarch64_cortex-a53.ipk |
d035314233265389f11385b0a3f979f391ddffdfc19e98bcc8308008bb6da5ab |
DOWNLOAD |
| uci-sample05_1.0-1_aarch64_cortex-a53.ipk |
3231ccbe1d0f47e0c10a881504739907ef9058a2765ef552e6962e35d2be90ed |
DOWNLOAD |
| uci-sample06_1.0-1_aarch64_cortex-a53.ipk |
2320b6e82bb616e89abeb62f30e57c6d80c2b7d101434fa9a905a7304d292e56 |
DOWNLOAD |
| uci-sample07_1.0-1_aarch64_cortex-a53.ipk |
d28c00f85838ea5682ebc2b5ee3b3faa21f14562d5240a27c901c397263f0fb5 |
DOWNLOAD |
| uci-sample08_1.0-1_aarch64_cortex-a53.ipk |
586695798434533bed97048c0a862a73ab76add069d8caa2e257acd3c93d93bf |
DOWNLOAD |
| uci-sample09_1.0-1_aarch64_cortex-a53.ipk |
1954fd0faf40da5f2f2708882f2e072989191a2c4a7f757341891fe31cedc2d2 |
DOWNLOAD |
| uci-sample10_1.0-1_aarch64_cortex-a53.ipk |
9030a9e8bba1c7ae95f4ff74ea033c646160711db807727b125a31e0406638de |
DOWNLOAD |
| uci-sample11_1.0-1_aarch64_cortex-a53.ipk |
93f9b0e885ca958f968418f77b0bb0f6aa168249ae5e779b38959bd80c5eb454 |
DOWNLOAD |
| uci-sample12_1.0-1_aarch64_cortex-a53.ipk |
9de9041948578e1ad500ef81a5e6d50fd60473a29ad421ffaee4ccc168b2885d |
DOWNLOAD |
| uci-sample13_1.0-1_aarch64_cortex-a53.ipk |
4deced02ab710e1710ffa9c0d281130aa32d72a2de900713ccee7df8222f89f9 |
DOWNLOAD |
Raspberry P4用パッケージ
| パッケージ |
ハッシュ(SHA256) |
ダウンロード |
| uci-sample01_1.0-1_aarch64_cortex-a72.ipk |
f7825cfc3b426d334345fcd1e37ee92e666adeaa7072f5e203d9623b819e98f5 |
DOWNLOAD |
| uci-sample02_1.0-1_aarch64_cortex-a72.ipk |
fe43bbe720c954a28300c44773e0b8508a1a51631e77c80659084540f8d6090f |
DOWNLOAD |
| uci-sample03_1.0-1_aarch64_cortex-a72.ipk |
f1eddca7aa055a63b046a3628614c8f74fe5d8ff45d77209a12e297c6f096d7f |
DOWNLOAD |
| uci-sample04_1.0-1_aarch64_cortex-a72.ipk |
42d89d724ce29255b25f7350005f38fda4ba7c7acf73f4ea63d5d002afea8250 |
DOWNLOAD |
| uci-sample05_1.0-1_aarch64_cortex-a72.ipk |
ba0e31f85f950cfa56cae16c3821373c2d62d90506debd1a0a8fc8e4e9198d23 |
DOWNLOAD |
| uci-sample06_1.0-1_aarch64_cortex-a72.ipk |
b2f5a467534e67c8bf65c20a2f7dba574cdda5941a253c9eb05ba56012d3bd70 |
DOWNLOAD |
| uci-sample07_1.0-1_aarch64_cortex-a72.ipk |
a1775d24369c39aaf3d715a50baa9ec9b4efe762bc6108af8c4ec42d64941dfb |
DOWNLOAD |
| uci-sample08_1.0-1_aarch64_cortex-a72.ipk |
0fb3bd7eeefad3b395627fdc216af089d64374f8fe219eab5111af56127d5335 |
DOWNLOAD |
| uci-sample09_1.0-1_aarch64_cortex-a72.ipk |
5fe4664a1288f07358c1cae071459d0ec389fa867b7a70db3506d11c048a379e |
DOWNLOAD |
| uci-sample10_1.0-1_aarch64_cortex-a72.ipk |
3d0370b92b021f7b527e7335b76a4bcaaf772152ae22171402b9739bd69e45ec |
DOWNLOAD |
| uci-sample11_1.0-1_aarch64_cortex-a72.ipk |
fdd398a5c76f9b2f641adb730efeff87a693b393ddf88e3595494a3b0642eb9f |
DOWNLOAD |
| uci-sample12_1.0-1_aarch64_cortex-a72.ipk |
9303f439211385249ead4bf97b467c611bceb3cddeba373df61a58bc629d5728 |
DOWNLOAD |
関連記事
参考文献