うたカモ技術ブログ

Linux OpenWrt

OpenWrt   サンプルプログラム掲載! UCIコマンド用C言語ライブラリ - libuci

post:     update: 

この記事で紹介するソースコードは自由に使っていただいて構いません。 アプリケーションの開発や自己学習にお役立て下さい。ただし、当ブログでは掲載するソースコードを流用・利用したことによる損害等につきましては 一切の責任を負いません。自己責任で利用お願いします。

今回は、OpenWrtアーキテクチャ要素の1つであるUCIコマンドのC言語コアライブラリ-libuciについて紹介します。

この記事は、開発者の方が自作アプリケーションにlibuciを使用して、UCIコマンドと同等な処理を直接プログラムに実装できる ようになることを目指して書いたものです。言わばリファレンス的な記事になります。

一般的なリファレンスにあるような無味乾燥な説明に留まらず、都度、サンプルプログラムを掲載して丁寧な解説を書くように心掛けました。

個人的には少しニッチすぎる記事かなと思いますが、誰かの参考になれば幸いです。

それでは行ってみましょう。

目次

  1. サンプルプログラムのダウンロード
  2. ビルド時のlibuciライブラリ指定方法
  3. libuciリファレンス
    1. uci_alloc_context
    2. uci_free_context
    3. uci_lookup_ptr
    4. uci_perror
    5. uci_get_errorstr
    6. uci_foreach_element
    7. uci_set
    8. uci_save
    9. uci_add_section
    10. uci_load
    11. uci_unload
    12. uci_add_list
    13. uci_del_list
    14. uci_reorder_section
    15. uci_rename
    16. uci_delete
    17. uci_commit
    18. uci_list_configs
    19. uci_set_savedir
    20. uci_set_confdir
    21. uci_add_delta_path
    22. uci_revert
    23. uci_parse_argument
    24. uci_set_backend
    25. uci_validate_text
    26. uci_parse_ptr
    27. uci_lookup_next
    28. uci_parse_section
    29. uci_hash_options
  4. サンプルソフトウェアのダウンロードリスト
  5. 関連記事
  6. 参考文献

サンプルプログラムのダウンロード

このリファレンスで紹介するサンプルプログラムは私のGitHubリポジトリ上に存在します。
ダウンロードしたい方は次のgitコマンドでクローンしてください。

git clone https://github.com/utakamo/UtakamoStudyApps.git

サンプルプログラムの一覧と簡単な説明を以下に掲載します。
学習を目的としていますので、処理をする上で全く意味をなさないプログラムもあります。予めご了承ください。

サンプルプログラム名 説明 同等なUCIコマンド
uci-sample01 uci_alloc_context関数を実行するプログラムです。 なし
uci-sample02 uci_lookup_ptr関数を実行するプログラム(その1)です。 なし
uci-sample03 uci_lookup_ptr関数を実行するプログラム(その2)です。 getコマンド
uci-sample04 uci_foreach_element関数を実行するプログラムです。 showコマンド
uci-sample05 uci_set関数を実行するプログラムです。 setコマンド
uci-sample06 uci_add_section関数を実行するプログラムです。 addコマンド
uci-sample07 uci_add_list関数を実行するプログラムです。 add_listコマンド
uci-sample08 uci_del_list関数を実行するプログラムです。 del_listコマンド
uci-sample09 uci_reorder_section関数を実行するプログラムです。 reorderコマンド
uci-sample10 uci_rename関数を実行するプログラムです。 renameコマンド
uci-sample11 uci_delete関数を実行するプログラムです。 deleteコマンド
uci-sample12 uci_commit関数を実行するプログラムです。 commitコマンド
uci-sample13 uci_revert関数を実行するプログラムです。 revertコマンド
uci-sample14 作成中 ---

お試しインストール(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)の詳細はこちらを参照してみてください。
//uci-sample01.c
#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();

    //UCIコンテキストの中身を一部表示させます
    //本来、この箇所に他のlibuci関数をUCIコンテキストを引数にして呼び出します。
    //これによって、UCIコンフィグレーションファイルを操作できます。
    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_ptruci_setuci_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構文として解析した結果を表示します。
//uci-sample02.c
#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();

    //今回取り上げるuci_lookup_ptr関数の使い方
    if (uci_lookup_ptr(ctx, &ptr, argv[1], true) != UCI_OK) {
        uci_perror(ctx, "specified args error");
        uci_free_context(ctx);
        return 1;
    }

    /****************************************/
    /*      uci_ptr member variables        */
    /****************************************/

    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); //詳細はuci-sample03
    printf("section address :%p\n", ptr.s); //詳細はuci-sample03
    printf("option address  :%p\n", ptr.o); //詳細はuci-sample03
    printf("last address    :%p\n\n", ptr.last); //詳細はuci-sample03

    uci_free_context(ctx);

    return 0;
}
実行結果例
次の引数を与えたときの実行結果を掲載します。
  1. network
  2. network.lan
  3. network.lan.ipaddr
  4. 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コマンドに相当します。
//uci-sample03.c
#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();

    //今回取り上げるuci_lookup_ptr関数の使い方
    if (uci_lookup_ptr (ctx, &ptr, argv[1], true) != UCI_OK) {
        uci_perror(ctx, "specified args error");
        uci_free_context(ctx);
        return 1;
    }

    //検索成功 中身を表示します。
    /****************************************/
    /*     uci_ptr member variables         */
    /****************************************/

    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>
//uci-sample04.c
#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);
    
    //uci show config.section.option (match)
    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));
        }
    }
        
    //uci show config.section.option (not match)
    else if (ptr.o == NULL && ptr.option != NULL)
        printf("not found\n");
    
    //uci show config.section
    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) {
        //struct uci_option *o = uci_to_option(e);
        //printf("%s ", o->v.string);
        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コンフィグ情報。
戻り値
  • 0
説明
本関数は名前付きセクションとオプションを作成または変更する処理です。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>
//uci-sample05.c
#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コンフィグ情報ポインタ。
戻り値
  • 0
本関数は指定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 本関数により、作成した匿名セクションポインタ。
戻り値
  • 0
説明
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コマンドと同等な処理を実現しています。
//uci-sample06.c
#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コンフィグ情報ポインタ。
戻り値
  • 0
説明
本関数は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コンフィグ情報ポインタ。
戻り値
  • 0
説明
任意のUCIコンフィグのリストデータを作成・追加します。
サンプルプログラム(uci-sample07)
uci add_listコマンドと同等な処理をするサンプルプログラムを掲載します。 uci_lookup_ptr関数により、操作対象のUCIコンフィグ情報を引き当てた上でuci_add_listで リストデータを作成します。
//uci-sample07.c
#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コンフィグ情報ポインタ。
戻り値
  • 0
説明
任意のUCIコンフィグのリストデータを削除します。
サンプルプログラム(uci-sample08)
uci del_listコマンドと同等な処理をするサンプルプログラムを掲載します。 uci_lookup_ptr関数により、操作対象のUCIコンフィグ情報を引き当てた上でuci_del_listで リストデータを削除します。
//uci-sample08.c
#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 移動先のセクション位置
戻り値
  • 0
説明
任意のUCIコンフィグのセクションを第3引数で示す位置に移動します。 セクションの位置はUCIコンフィグレーションファイルの先頭から順に数えられます。 一番先頭のセクション位置は0です。
サンプルプログラム(uci-sample09)
uci reorderコマンドと同等な処理をするサンプルプログラムを掲載します。 uci_lookup_ptr関数によって、操作対象のUCIコンフィグ情報を引き当てた上でuci_reorder_section により特定セクションを指定位置に移動させます。
//uci-sample09.c
#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コンフィグ情報ポインタ。
戻り値
  • 0
説明
任意のUCIコンフィグのセクション名を変更します。
サンプルプログラム(uci-sample10)
uci renameコマンドと同等な処理をするサンプルプログラムを掲載します。 uci_lookup_ptr関数によって、操作対象のUCIコンフィグ情報を引き当てた上でuci_rename により特定セクションの名前を変更します。
//uci-sample10.c
#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コンフィグ情報ポインタ。
戻り値
  • 0
説明
任意のUCIコンフィグのセクション・オプションを削除します。
サンプルプログラム(uci-sample11)
uci deleteコマンドと同等な処理をするサンプルプログラムを掲載します。 uci_lookup_ptr関数によって、操作対象のUCIコンフィグ情報を引き当てた上でuci_delete により特定セクション・オプションを削除します。
//uci-sample11.c
#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:消去しない。
戻り値
  • 0
説明
ステージング領域(デフォルトでは/tmp/.uci)に存在する変更差分をFLASH領域(デフォルトでは/etc/config) の対応するUCIコンフィグレーションファイルにコピー(マージ)します。
サンプルプログラム(uci-sample12)
uci commitコマンドと同等な処理をするサンプルプログラムを掲載します。
//uci-sample12.c
#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();

    //target package
    if (argc == 2) {
        commit_one_package(ctx, argv[1]); 
    }

    else {
        commit_all_package(ctx);
    }

    uci_free_context(ctx);

    return 0;
}

//commit one package
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;
        }
    }
}

//commit all package
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 変更先ディレクトリパス。
戻り値
作成中
説明
作成中
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コンフィグ情報ポインタ。
戻り値
  • 0
説明
ステージング領域(デフォルトでは/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 調査中
作成中
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 調査中
説明
本関数は、第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 行ポインタ
説明
作成中
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 調査中
struct uci_option **tb 調査中
説明
作成中
uint32_t uci_hash_options(struct uci_option **tb, int n_opts)
<型> <引数名> 説明
struct uci_option **tb 調査中
int n_opts 調査中
作成中

サンプルソフトウェアのダウンロードリスト

Webブラウザを通してサンプルソフトウェアをダウンロードするためのリンクを貼ります。 ダウンロードしたらOpenWrtデバイスにftpscpを利用してアップロードしてみてください。

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

関連記事

参考文献