chapter 03-02

資料的存取 (用戶端程式)

此章節說明用戶端程式如何透過提供的介面存取資料.


Makefile 的編譯參數 :
# 路徑設定.
MCM_PATH       = mint_cm
MCM_LULIB_PATH = $(MCM_PATH)/mcm_lib/mcm_lulib


# 標頭檔路徑.
INCLUDE_PATH = -I$(MCM_PATH)
# 函式庫路徑.
LIBRARY_PATH = -L$(MCM_LULIB_PATH)

# 使用靜態鏈結或動態鏈結的鏈結參數.
USE_STATIC_MCM_LIB = YES
ifeq (${USE_STATIC_MCM_LIB}, YES)
LIBRARY_FILE = $(MCM_LULIB_PATH)/mcm_lulib_api.a
else
LIBRARY_FILE = -lmcm_lulib_api
endif

MintCM 的用戶端函式庫在 mint_cm/mcm_lib/mcm_lulib.
使用動態鏈結必須將 libmcm_lulib_api.so 複製到系統的 lib 目錄.

需要的標頭檔 :
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"



變數格式的說明

這邊先說明使用 mcm_lulib_api.so 提供的函式的變數的用途和格式.


使用的資料模型範例, 參考 #02-02#.


[struct mcm_lulib_lib_t *this_lulib]
用來儲存 libmcm_lulib_api.so 使用時需要的資訊.
會用到的結構成員 :
[char *socket_path]
伺服器的位址路徑. [詳細]
[MCM_DTYPE_LIST_TD call_from]
表示是誰要求資料存取.
MCM_CALL_FROM
(mint_cm/mcm_lib/mcm_lheader/mcm_connect.h)
MCM_CFROM_BOOT 表示是開機的第一次呼叫
MCM_CFROM_USER 表示是用戶端程式在請求
MCM_CFROM_KERNEL 表示是核心端程式在請求
MCM_CFROM_WEB 表示是用網頁端程式在請求
用戶端程式使用 MCM_CFROM_USER.
[MCM_DTYPE_LIST_TD session_permission]
表示資料存取的模式.
MCM_SESSION_PERMISSION
(mint_cm/mcm_lib/mcm_lheader/mcm_connect.h)
MCM_SPERMISSION_RO 唯讀
MCM_SPERMISSION_RW 讀寫
如果只要讀取資料, 使用 MCM_SPERMISSION_RO, 如果要修改 (設定/增加/刪除) 資料, 使用 MCM_SPERMISSION_RW.
[MCM_DTYPE_USIZE_TD session_stack_size]
伺服器端負責此連線的執行緒的堆疊大小.
0 系統預設值
可以使用系統指令 ulimit -s 查看 (單位是 KB)
或是使用系統函式 getrlimit() + RLIMIT_STACK 查看
1 ~ N 指定的值
小於系統最小限制 PTHREAD_STACK_MIN 的話會改用最小值
一般 Linux 的執行緒預設的堆疊大小是 8MB, 如果沒有需要執行內部模組的話不需要這麼多堆疊空間, 可以降低堆疊大小減少記憶體的使用. 而如果需要執行內部模組的話, 因為內部模組函式的內容是客制化的, 所以需要的堆疊空間不固定 (區域變數的多寡和函式呼叫的層數都會影響需要的堆疊空間), 就有可能需要更大的堆疊空間.


[char *mask_path]
取得 group 的資訊的路徑.
格式 :
$(group-info-1).$(group-info-2). - - - .$(group-info-N)

$(entry-info)
由 group 名稱和 mask 資訊所組成的一小段路徑.
格式 :
gs 類型 : $(group-name)
gd 類型 : $(group-name).*


$(group-name) group 的名稱
* 表示 gd 類型的 group 的 mask 符號

範例 :
device
表示 device

device.system
表示 system

device.vap.*
表示 vap

device.vap.*.extra
表示 extra

device.vap.*.station.*
表示 station

device.limit.*
表示 limit

device.client.*
表示 client



[char *mix_path]
存取多個 entry 的路徑.

格式 :
$(group-info-NonLast). - - - .($(group-info-LastGD) or $(group-info-LastGS))

$(entry-info-NonLast)
由 group 名稱和 index / key 資訊所組成的一小段路徑 (非最後一段路徑).
格式 :
gs 類型 :
$(group-name)

gd 類型 :
index 模式 : $(group-name).@$(entry-index)
  key 模式 : $(group-name).#$(entry-key)

[$(entry-info-LastGD)]
由 gd 類型的 group 名稱和 mask 資訊所組成的一小段路徑 (最後一段路徑).
格式 :
$(group-name).*

[$(entry-info-LastGS)]
由 gs 類型的 group 名稱所組成的一小段路徑 (最後一段路徑).
格式 :
$(group-name)


index / key 模式的差異主要是針對 entry 的搜尋方式.
index 尋找 group 內的第幾筆 entry (1, 2, 3, ...)
key 尋找 group 內 key 值相符的 entry (35, 10, 21, ...)
實際使用上有分成 :
index / key 模式 路徑上的 $(entry-index/key) 部分可以 index / key 混用
key 模式 路徑上的 $(entry-index/key) 部分只允許使用 key

$(group-name) group 的名稱
@ entry index 的前綴符號
$(entry-index) entry 的 index 值, 1 ~ 4294967295 (MCM_DTYPE_EK_TD)
# entry key 的前綴符號
$(entry-key) entry 的 key 值, 1 ~ 4294967295 (MCM_DTYPE_EK_TD)
* 表示 gd 類型的 group 的 mask 符號

範例 :
device
表示 device

device.system
表示 system

device.vap.*
表示 vap

device.vap.@1.extra
表示 vap 的第 1 筆 entry 的 extra

device.vap.@3.station.*
表示 vap 的第 3 筆 entry 的 station

device.vap.#71.station.*
表示 vap 內 key 為 71 的 entry 的 station

device.limit.*
表示 limit

device.client.*
表示 client



[char *full_path]
存取的目標 entry 或 member 的路徑.

entry 格式 :
$(group-info-1).$(group-info-2). - - - .$(group-info-N)

$(entry-info)
由 group 名稱和 index / key 資訊所組成的一小段路徑.
格式 :
gs 類型 :
$(group-name)

gd 類型 :
index 模式 : $(group-name).@$(entry-index)
  key 模式 : $(group-name).#$(entry-key)


member 格式 :
$(group-info-1).$(group-info-2). - - - .$(group-info-N).$(member-name)


index / key 模式的差異主要是針對 entry 的搜尋方式.
index 尋找 group 內的第幾筆 entry (1, 2, 3, ...)
key 尋找 group 內 key 值相符的 entry (35, 10, 21, ...)
實際使用上有分成 :
index / key 模式 路徑上的 $(entry-index/key) 部分可以 index / key 混用
key 模式 路徑上的 $(entry-index/key) 部分只允許使用 key

$(group-name) group 的名稱
@ entry index 的前綴符號
$(entry-index) entry 的 index 值, 1 ~ 4294967295 (MCM_DTYPE_EK_TD)
# entry key 的前綴符號
$(entry-key) entry 的 key 值, 1 ~ 4294967295 (MCM_DTYPE_EK_TD)
$(member-name) member 的名稱

範例 (entry) :
device
表示 device 的全部

device.system
表示 system 的全部

device.vap.#71
表示 vap 內 key 為 71 的 entry

device.vap.@29.extra
表示 vap 的第 29 筆 entry 的 extra

device.vap.#15.station.@6
表示 vap 內 key 為 45 的 entry 的 station 的第 6 筆 entry

device.limit.#1
表示 limit 內 key 為 1 的 entry

device.client.@1
表示 client 的第 1 筆 entry


範例 (member) :
device.product
表示 device 的 product

device.system.uptime
表示 system 的 uptime

device.vap.@3.ekey
表示 vap 的第 3 筆 entry 的 ekey

device.vap.#12.extra.hidden
表示 vap 內 key 為 12 的 entry 的 extra 的 hidden

device.vap.@7.station.#26.mac_addr
表示 vap 的第 7 筆 entry 的 station 內 key 為 26 的 entry 的 mac_addr

device.limit.@23.priority
表示 limit 內第 23 筆 entry 的 priority

device.client.#6.location_x
表示 client 內 key 為 6 的 location_x



[char *insert_path]
在增加 entry 時, 指定要插入到哪個 entry 之前.

格式 :
index 模式 : @$(entry-index)
  key 模式 : #$(entry-key)


index / key 模式的差異主要是針對 entry 的搜尋方式.
index 要插入到 group 內的第幾筆 entry (1, 2, 3, ...) 之前
key 要插入到 group 內 key 值相符的 entry (35, 10, 21, ...) 之前

@ entry index 的前綴符號
$(entry-index) entry 的 index 值, 1 ~ 4294967295 (MCM_DTYPE_EK_TD)
# entry key 的前綴符號
$(entry-key) entry 的 key 值, 1 ~ 4294967295 (MCM_DTYPE_EK_TD)

注意事項.
如果輸入 NULL"" (空字串), 表示增加的 entry 要放在串列的尾端
如果目標 index 或 key 不存在, 則增加的 entry 會放在串列的尾端

範例 :
@1
表示插入到第 1 筆 entry 之前, 也就是插入的 entry 變第 1 筆, 被插入的 entry 變第 2 筆

#21
表示插入到 key 為 21 的 entry 之前

"" (空字串)
表示放在串列的尾端

NULL
表示放在串列的尾端



註 :
使用 mix_path, full_path, insert_path 存取資料時, 在資料的搜索速度上 key 模式會優於 index 模式.


存取 member 資料的變數的型態
根據在資料模型中指定的資料類型 [詳細], 需要使用對應的型態的變數來紀錄.
$(type) 對應型態 printf 格式
ek MCM_DTYPE_EK_TD MCM_DTYPE_EK_PF
rk MCM_DTYPE_RK_TD MCM_DTYPE_RK_PF
isc MCM_DTYPE_ISC_TD MCM_DTYPE_ISC_PF
iuc MCM_DTYPE_IUC_TD MCM_DTYPE_IUC_PF
iss MCM_DTYPE_ISS_TD MCM_DTYPE_ISS_PF
ius MCM_DTYPE_IUS_TD MCM_DTYPE_IUS_PF
isi MCM_DTYPE_ISI_TD MCM_DTYPE_ISI_PF
iui MCM_DTYPE_IUI_TD MCM_DTYPE_IUI_PF
isll MCM_DTYPE_ISLL_TD MCM_DTYPE_ISLL_PF
iull MCM_DTYPE_IULL_TD MCM_DTYPE_IULL_PF
ff MCM_DTYPE_FF_TD MCM_DTYPE_FF_PF
fd MCM_DTYPE_FD_TD MCM_DTYPE_FD_PF
fld MCM_DTYPE_FLD_TD MCM_DTYPE_FLD_PF
s:$(size) MCM_DTYPE_S_TD (buffer array) MCM_DTYPE_S_PF
b:$(size) MCM_DTYPE_B_TD (buffer array) MCM_DTYPE_B_PF


存取 entry 資料的變數的型態
可以當作 struct 來存取, member 是成員變數.
必須先寫好資料模型檔並編譯完成, mint_cm/mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h 會產生對應的結構資料.
例如 :
vap 會被編譯出 :

// device.vap.*
struct mcm_dv_device_vap_t
{
    MCM_DTYPE_EK_TD ekey;
    MCM_DTYPE_S_TD ssid[MCM_BSIZE_DEVICE_VAP_SSID];
    MCM_DTYPE_IUS_TD channel;
} /*__attribute__((packed))*/;


如果需要修改結構的對齊方式, 修改 mint_cm/mcm_build/mcm_build.c 並重新編譯全部.
#define MCM_DATA_EXINFO_DATA_VALUE_ATTRIBUTE "/*__attribute__((packed))*/"



可用的函式

mcm_lulib_init
初始化, 發出資料存取請求.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
需要先設定好會用到的結構成員 :
socket_path [詳細]
call_from [詳細]
session_permission [詳細]
session_stack_size [詳細]
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    struct mcm_lulib_lib_t self_lulib;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 資料存取.
    // ...

FREE_01:
    return 0;
}

mcm_lulib_exit
使用完畢, 釋放使用權.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 的資料
回傳 說明
>= MCM_RCODE_PASS 成功

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    struct mcm_lulib_lib_t self_lulib;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 資料存取.
    // ...

    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_get_max_count
取得資料筆數上限, 也就是資料模型中的 $(max) 值.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
mask_path
目標的路徑 [詳細]
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_EK_TD max_count;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 範例 : 取得 device.system 的資料筆數上限.
    // 路徑 : "device.system"
    path1 = "device.system";
    if(mcm_lulib_get_max_count(&self_lulib, path1, &max_count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_max_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, max_count);

    // 範例 : 取得 device.vap.* 的資料筆數上限.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lulib_get_max_count(&self_lulib, path1, &max_count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_max_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, max_count);

    // 範例 : 取得 device.vap.*.station.* 的資料筆數上限.
    // 路徑 : "device.vap.*.station.*"
    path1 = "device.vap.*.station.*";
    if(mcm_lulib_get_max_count(&self_lulib, path1, &max_count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_max_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, max_count);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}


除了上述方式外, 可以使用另一種方式取得 group 的資料筆數上限.
必須先寫好資料模型檔並編譯完成, mint_cm/mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h 會產生對應的資料定義.

#02-02# 的資料模型為例, 會產生 :
// device
#define MCM_MCOUNT_DEVICE_MAX_COUNT 1U

// device.system
#define MCM_MCOUNT_DEVICE_SYSTEM_MAX_COUNT 1U

// device.vap.*
#define MCM_MCOUNT_DEVICE_VAP_MAX_COUNT 16U

// device.vap.*.extra
#define MCM_MCOUNT_DEVICE_VAP_EXTRA_MAX_COUNT 1U

// device.vap.*.station.*
#define MCM_MCOUNT_DEVICE_VAP_STATION_MAX_COUNT 32U

// device.limit.*
#define MCM_MCOUNT_DEVICE_LIMIT_MAX_COUNT 64U

// device.client.*
#define MCM_MCOUNT_DEVICE_CLIENT_MAX_COUNT 128U

定義內的值就是實際的 $(max) 值.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;

    // 範例 : 取得 device.system 的資料筆數上限.
    // 路徑 : "device.system"
    path1 = "device.system";
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, MCM_MCOUNT_DEVICE_SYSTEM_MAX_COUNT);

    // 範例 : 取得 device.vap.* 的資料筆數上限.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, MCM_MCOUNT_DEVICE_VAP_MAX_COUNT);

    // 範例 : 取得 device.vap.*.station.* 的資料筆數上限.
    // 路徑 : "device.vap.*.station.*"
    path1 = "device.vap.*.station.*";
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, MCM_MCOUNT_DEVICE_VAP_STATION_MAX_COUNT);

    return 0;
}

mcm_lulib_get_count
取得目前的資料筆數.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_EK_TD count;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 指定目標路徑, 再使用函式取得.
    // 對於多層的目標, 可以使用 index + key 模式取值.

    // 範例 : 取得 device.system 的資料筆數. (對於 gs 類型 group, 總是 1)
    // 路徑 : "device.system"
    path1 = "device.system";
    if(mcm_lulib_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 取得 device.vap.* 的資料筆數.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lulib_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 取得 device.vap.@2.station.* 的資料筆數.
    // 路徑 : "device.vap.@2.station.*"
    path1 = "device.vap.@2.station.*";
    if(mcm_lulib_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 取得 device.vap.#23.station.* 的資料筆數.
    // 路徑 : "device.vap.#23.tation.*"
    path1 = "device.vap.#23.station.*";
    if(mcm_lulib_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_get_alone
讀出 member 的資料.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[member 格式][index / key 模式]
void *
data_buf
紀錄資料的變數的緩衝 (變數的資料型態 [詳細])
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_B_TD serial_number[MCM_BSIZE_DEVICE_SERIAL_NUMBER];
    MCM_DTYPE_FD_TD loading;
    MCM_DTYPE_EK_TD ekey;
    MCM_DTYPE_ISS_TD tx_power;
    MCM_DTYPE_S_TD mac_addr[MCM_BSIZE_DEVICE_VAP_STATION_MAC_ADDR];
    MCM_DTYPE_RK_TD rule;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 指定目標路徑, 指定目標的資料類型, 指定儲存的變數.
    // 對於 gd 類型的 group, 可以使用 index + key 模式.

    // 範例 : 讀出 device.serial_number
    // 路徑 : "device.serial_number"
    // 型態 : b -> MCM_DTYPE_B_TD
    // 變數 : serial_number
    path1 = "device.serial_number";
    if(mcm_lulib_get_alone(&self_lulib, path1, serial_number) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         serial_number[0], serial_number[1], serial_number[2], serial_number[3],
         serial_number[4], serial_number[5], serial_number[6], serial_number[7],
         serial_number[8], serial_number[9]);

    // 範例 : 讀出 device.system.loading
    // 路徑 : "device.system.loading"
    // 型態 : fd -> MCM_DTYPE_FD_TD
    // 變數 : loading
    path1 = "device.system.loading";
    if(mcm_lulib_get_alone(&self_lulib, path1, &loading) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_FD_PF, path1, loading);

    // 範例 : 讀出 device.vap.@3.ekey
    // 路徑 : "device.vap.@3.ekey"
    // 型態 : ek -> MCM_DTYPE_EK_TD
    // 變數 : vap_ekey
    path1 = "device.vap.@3.ekey";
    if(mcm_lulib_get_alone(&self_lulib, path1, &ekey) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_EK_PF, path1, ekey);

    // 範例 : 讀出 device.vap.#8.extra.tx_power
    // 路徑 : "device.vap.#8.extra.tx_power"
    // 型態 : iss -> MCM_DTYPE_ISS_TD
    // 變數 : tx_power
    path1 = "device.vap.#8.extra.tx_power";
    if(mcm_lulib_get_alone(&self_lulib, path1, &tx_power) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_ISS_PF, path1, tx_power);

    // 範例 : 讀出 device.vap.@2.station.#30.mac_addr
    // 路徑 : "device.vap.@2.station.#30.mac_addr"
    // 型態 : s -> MCM_DTYPE_S_TD
    // 變數 : mac_addr
    path1 = "device.vap.@2.station.#30.mac_addr";
    if(mcm_lulib_get_alone(&self_lulib, path1, mac_addr) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_S_PF, path1, mac_addr);

    // 範例 : 讀出 device.vap.#15.station.@2.rule
    // 路徑 : "device.vap.#15.station.@2.rule"
    // 型態 : rk -> MCM_DTYPE_RK_TD
    // 變數 : mac_addr
    path1 = "device.vap.#15.station.@2.rule";
    if(mcm_lulib_get_alone(&self_lulib, path1, &rule) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_RK_PF, path1, rule);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_set_alone
將資料寫入 member.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[member 格式][index / key 模式]
void *
data_con
寫入的資料 (變數的資料型態 [詳細])
MCM_DTYPE_USIZE_TD
data_len
寫入的資料的長度
字串類型填入字串長度, 其他類型填入變數大小
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  因為 ek 類型的 member 是唯讀的, 所以不可寫入.
03.  字串類型的資料在寫入時必須是 UTF-8 格式.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_S_TD descript[MCM_BSIZE_DEVICE_DESCRIPT];
    MCM_DTYPE_B_TD serial_number[MCM_BSIZE_DEVICE_SERIAL_NUMBER];
    MCM_DTYPE_FD_TD loading;
    MCM_DTYPE_IUI_TD channel;
    MCM_DTYPE_ISC_TD hidden;
    MCM_DTYPE_RK_TD rule;
    MCM_DTYPE_USIZE_TD i;

    srand(time(NULL));

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 設定 device.descript
    // 路徑 : "device.descript"
    // 型態 : s -> MCM_DTYPE_S_TD
    // 變數 : descript / strlen(descript)
    path1 = "device.descript";
    snprintf(descript, sizeof(descript), "network-device-%02u", rand() % 100);
    DMSG("[set-alone] %s = " MCM_DTYPE_S_PF, path1, descript);
    if(mcm_lulib_set_alone(&self_lulib, path1, descript, strlen(descript)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.serial_number
    // 路徑 : "device.serial_number"
    // 型態 : b -> MCM_DTYPE_B_TD
    // 變數 : serial_number / sizeof(serial_number)
    path1 = "device.serial_number";
    for(i = 0; i < sizeof(serial_number); i++)
        serial_number[i] = rand() % 256;
    DMSG("[set-alone] %s = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         serial_number[0], serial_number[1], serial_number[2], serial_number[3],
         serial_number[4], serial_number[5], serial_number[6], serial_number[7],
         serial_number[8], serial_number[9]);
    if(mcm_lulib_set_alone(&self_lulib, path1, serial_number, sizeof(serial_number))
                           < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.system.loading
    // 路徑 : "device.system.loading"
    // 型態 : fd -> MCM_DTYPE_FD_TD
    // 變數 : loading / sizeof(loading)
    path1 = "device.system.loading";
    loading = ((MCM_DTYPE_FD_TD) 20000) / ((rand() % 100) + 1);
    DMSG("[set-alone] %s = " MCM_DTYPE_FD_PF, path1, loading);
    if(mcm_lulib_set_alone(&self_lulib, path1, &loading, sizeof(loading)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@1.channel
    // 路徑 : "device.vap.@1.channel"
    // 型態 : iui -> MCM_DTYPE_IUI_TD
    // 變數 : channel / sizeof(channel)
    path1 = "device.vap.@1.channel";
    channel = rand() % 200;
    DMSG("[set-alone] %s = " MCM_DTYPE_IUI_PF, path1, channel);
    if(mcm_lulib_set_alone(&self_lulib, path1, &channel, sizeof(channel)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.#8.extra.hidden
    // 路徑 : "device.vap.#8.extra.hidden"
    // 型態 : isc -> MCM_DTYPE_ISC_TD
    // 變數 : hidden / sizeof(hidden)
    path1 = "device.vap.#8.extra.hidden";
    hidden = rand() % 2;
    DMSG("[set-alone] %s = " MCM_DTYPE_ISC_PF, path1, hidden);
    if(mcm_lulib_set_alone(&self_lulib, path1, &hidden, sizeof(hidden)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@2.station.#33.rule
    // 路徑 : "device.vap.@2.station.#33.rule"
    // 型態 : rk -> MCM_DTYPE_RK_TD
    // 變數 : rule / sizeof(rule)
    path1 = "device.vap.@2.station.#33.rule";
    rule = rand() % 50;
    DMSG("[set-alone] %s = " MCM_DTYPE_RK_PF, path1, rule);
    if(mcm_lulib_set_alone(&self_lulib, path1, &rule, sizeof(rule)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_get_entry
讀取 entry 的資料.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
void *
data_buf
紀錄資料的變數的緩衝 (變數的資料型態 [詳細])
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    struct mcm_dv_device_t device_v;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_extra_t extra_v;
    struct mcm_dv_device_vap_station_t station_v;
    struct mcm_dv_device_limit_t limit_v;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 對於 gd 類型的 group, 可以使用 index + key 模式.

    // 範例 : 讀出 device
    // 路徑 : "device"
    // 型態 : struct mcm_dv_device_t
    // 變數 : device_v
    path1 = "device";
    if(mcm_lulib_get_entry(&self_lulib, path1, &device_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.descript = " MCM_DTYPE_S_PF,
         path1, device_v.descript);
    DMSG("[get-entry] %s.serial_number = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         device_v.serial_number[0], device_v.serial_number[1], device_v.serial_number[2],
         device_v.serial_number[3], device_v.serial_number[4], device_v.serial_number[5],
         device_v.serial_number[6], device_v.serial_number[7], device_v.serial_number[8],
         device_v.serial_number[9]);

    // 範例 : 讀出 device.vap.@1
    // 路徑 : "device.vap.@1"
    // 類型 : struct mcm_dv_device_vap_t
    // 變數 : vap_v
    path1 = "device.vap.@1";
    if(mcm_lulib_get_entry(&self_lulib, path1, &vap_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path1, vap_v.ekey);
    DMSG("[get-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[get-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);

    // 範例 : 讀出 device.vap.#23.extra
    // 路徑 : "device.vap.#23.extra"
    // 類型 : struct mcm_dv_device_vap_extra_t
    // 變數 : extra_v
    path1 = "device.vap.#23.extra";
    if(mcm_lulib_get_entry(&self_lulib, path1, &extra_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.hidden = " MCM_DTYPE_ISC_PF, path1, extra_v.hidden);
    DMSG("[get-entry] %s.tx_power = " MCM_DTYPE_ISS_PF,
         path1, extra_v.tx_power);

    // 範例 : 讀出 device.vap.@2.station.#30
    // 路徑 : "device.vap.@2.station.#30"
    // 類型 : struct mcm_dv_device_vap_station_t
    // 變數 : station_v
    path1 = "device.vap.@2.station.#30";
    if(mcm_lulib_get_entry(&self_lulib, path1, &station_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path1, station_v.ekey);
    DMSG("[get-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[get-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);

    // 範例 : 讀出 device.limit.#6
    // 路徑 : "device.limit.#6"
    // 類型 : struct mcm_dv_device_limit_t
    // 變數 : limit_v
    path1 = "device.limit.#6";
    if(mcm_lulib_get_entry(&self_lulib, path1, &limit_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path1, limit_v.ekey);
    DMSG("[get-entry] %s.name = " MCM_DTYPE_S_PF, path1, limit_v.name);
    DMSG("[get-entry] %s.priority = " MCM_DTYPE_ISI_PF, path1, limit_v.priority);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_set_entry
將資料寫入 entry.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
void *
data_con
寫入的資料 (變數的資料型態 [詳細])
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  因為 ek 類型的 member 是唯讀的, 所以資料庫內 ek 的數值不會被寫入的資料覆蓋.
03.  字串類型的資料在寫入時必須是 UTF-8 格式.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    struct mcm_dv_device_t device_v;
    struct mcm_dv_device_system_t system_v;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_extra_t extra_v;
    struct mcm_dv_device_vap_station_t station_v;
    MCM_DTYPE_USIZE_TD i;

    srand(time(NULL));

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 設定 device
    // 路徑 : "device"
    // 型態 : struct mcm_dv_device_t
    // 變數 : device_v
    path1 = "device";
    memset(&device_v, 0, sizeof(device_v));
    snprintf(device_v.descript, sizeof(device_v.descript), "network-device-%02u", rand() % 100);
    for(i = 0; i < sizeof(device_v.serial_number); i++)
        device_v.serial_number[i] = rand() % 256;
    DMSG("[set-entry] %s.descript = " MCM_DTYPE_S_PF, path1, device_v.descript);
    DMSG("[set-entry] %s.serial_number = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         device_v.serial_number[0], device_v.serial_number[1], device_v.serial_number[2],
         device_v.serial_number[3], device_v.serial_number[4], device_v.serial_number[5],
         device_v.serial_number[6], device_v.serial_number[7], device_v.serial_number[8],
         device_v.serial_number[9]);
    if(mcm_lulib_set_entry(&self_lulib, path1, &device_v, sizeof(device_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.system
    // 路徑 : "device.system"
    // 型態 : struct mcm_dv_device_system_t
    // 變數 : system_v
    path1 = "device.system";
    memset(&system_v, 0, sizeof(system_v));
    snprintf(system_v.date, sizeof(system_v.date), "2016/05/%u", rand() % 30);
    snprintf(system_v.ip_addr, sizeof(system_v.ip_addr), "192.168.1.%u", rand() % 250);
    system_v.uptime = rand();
    system_v.loading = ((MCM_DTYPE_FD_TD) 25000) / ((rand() % 100) + 1);
    DMSG("[set-entry] %s.date = " MCM_DTYPE_S_PF, path1, system_v.date);
    DMSG("[set-entry] %s.ip_addr = " MCM_DTYPE_S_PF, path1, system_v.ip_addr);
    DMSG("[set-entry] %s.uptime = " MCM_DTYPE_IULL_PF, path1, system_v.uptime);
    DMSG("[set-entry] %s.loading = " MCM_DTYPE_FD_PF, path1, system_v.loading);
    if(mcm_lulib_set_entry(&self_lulib, path1, &system_v, sizeof(system_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@1
    // 路徑 : "device.vap.@1"
    // 型態 : struct mcm_dv_device_vap_t
    // 變數 : vap_v
    path1 = "device.vap.@1";
    memset(&vap_v, 0, sizeof(vap_v));
    snprintf(vap_v.ssid, sizeof(vap_v.ssid), "access-%u", rand() % 100);
    vap_v.channel = rand() % 200;
    DMSG("[set-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[set-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);
    if(mcm_lulib_set_entry(&self_lulib, path1, &vap_v, sizeof(vap_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.#23.extra
    // 路徑 : "device.vap.#23.extra"
    // 型態 : struct mcm_dv_device_vap_extra_t
    // 變數 : extra_v
    path1 = "device.vap.#23.extra";
    memset(&extra_v, 0, sizeof(extra_v));
    extra_v.hidden = rand() % 2;
    extra_v.tx_power = (rand() % 20) - 10;
    DMSG("[set-entry] %s.hidden = " MCM_DTYPE_ISC_PF, path1, extra_v.hidden);
    DMSG("[set-entry] %s.tx_power = " MCM_DTYPE_ISS_PF, path1, extra_v.tx_power);
    if(mcm_lulib_set_entry(&self_lulib, path1, &extra_v, sizeof(extra_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@2.station.#30
    // 路徑 : "device.vap.@2.station.#30"
    // 型態 : struct mcm_dv_device_vap_station_t
    // 變數 : station_v
    path1 = "device.vap.@2.station.#30";
    memset(&station_v, 0, sizeof(station_v));
    snprintf(station_v.mac_addr, sizeof(station_v.mac_addr), "00:11:22:AA:BB:%02X", rand() % 255);
    station_v.rule = rand() % 50;
    DMSG("[set-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[set-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);
    if(mcm_lulib_set_entry(&self_lulib, path1, &station_v, sizeof(station_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_add_entry
增加一筆 entry.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
加入的目標必須是 [key 模式]
char *
insert_path
要插入到何處的路徑 [詳細]
[index 模式] / [key 模式]
void *
data_con
寫入的資料 (變數的資料型態 [詳細])
可為 NULL, 表示使用初始值 (資料模型中設的 $(default)) [詳細]
MCM_DTYPE_USIZE_TD
data_len
寫入的資料的長度
若 data_con 是 NULL, 則為 0
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  路徑可以是 [indxe / key 模式], 但是最後一段要加入的目標必須是 [key 模式].
03.  增加 entry 需要指定新的 key (不可和存在的 entry 的 key 相同).
04.  key 值會使用 full_path 的值, data_con 內的 key 值會被忽略.
05.  增加多層資料時, 要逐層增加.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_station_t station_v;

    srand(time(NULL));

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 路徑可以是 [indxe / key 模式], 但是最後一段要加入的目標必須是 [key 模式].
    // 增加 entry 需要指定新的 key (不可和存在的 entry 的 key 相同).
    // key 值會使用 full_path 的值, data_con 內的 key 值會被忽略.
    // 增加多層資料時, 要逐層增加.
    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 增加 device.vap.#123
    // 路徑 : "device.vap.#123"
    // 插入 : 放在串列尾端 (NULL)
    // 類型 : struct mcm_dv_device_vap_t
    // 變數 : vap_v / sizeof(vap_v)
    // 加入的目標 (vap) 必須是 key 模式.
    path1 = "device.vap.#123";
    memset(&vap_v, 0, sizeof(vap_v));
    snprintf(vap_v.ssid, sizeof(vap_v.ssid), "vap-%u", rand() % 100);
    vap_v.channel = rand() % 200;
    DMSG("[add-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[add-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);
    if(mcm_lulib_add_entry(&self_lulib, path1, NULL, &vap_v, sizeof(vap_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_add_entry(%s) fail", path1);
        goto FREE_02;
    }
    // 如果 parent-group 是 gd 類型的 gs 類型 group, 當 parent-group 增加
    // entry 時, 也會一併被增加.
    // 以 device.vap.*.extra 為例, 當 device.vap.* 增加 entry,
    // 對應的 extra 也會被增加, 被增加的 extra 內容為資料模型中設定的初始值.

    // 範例 : 增加 device.vap.@3.station.#111
    // 路徑 : "device.vap.@3.station.#111"
    // 插入 : 放在串列尾端 ("")
    // 類型 : struct mcm_dv_device_vap_station_t
    // 變數 : station_v / sizeof(station_v)
    // 加入的目標 (station) 必須是 key 模式.
    path1 = "device.vap.@3.station.#111";
    memset(&station_v, 0, sizeof(station_v));
    snprintf(station_v.mac_addr, sizeof(station_v.mac_addr), "00:1a:2b:3c:4d:%02x", rand() % 255);
    station_v.rule = rand() % 50;
    DMSG("[add-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[add-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);
    if(mcm_lulib_add_entry(&self_lulib, path1, "", &station_v, sizeof(station_v))
                           < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_add_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 增加 device.vap.#234.station.#1
    // 路徑 : "device.vap.#234.station.#1"
    // 插入 : 插入到第 1 筆 entry 之前 (@1)
    // 類型 : struct mcm_dv_device_vap_t
    // 變數 : vap_v / sizeof(vap_v)
    // 增加多層資料時, 要逐層增加.
    // device.vap.#234 並不存在, 先增加.
    path1 = "device.vap.#234";
    memset(&vap_v, 0, sizeof(vap_v));
    snprintf(vap_v.ssid, sizeof(vap_v.ssid), "vap-%u", rand() % 100);
    vap_v.channel = rand() % 200;
    DMSG("[add-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[add-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);
    if(mcm_lulib_add_entry(&self_lulib, path1, "", &vap_v, sizeof(vap_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_add_entry(%s) fail", path1);
        goto FREE_02;
    }
    // 接著增加 device.vap.#234.station.#1
    path1 = "device.vap.#234.station.#1";
    memset(&station_v, 0, sizeof(station_v));
    snprintf(station_v.mac_addr, sizeof(station_v.mac_addr), "00:aa:bb:cc:dd:%02x", rand() % 255);
    station_v.rule = rand() % 50;
    DMSG("[add-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[add-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);
    if(mcm_lulib_add_entry(&self_lulib, path1, "@1", &station_v, sizeof(station_v))
                           < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_add_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 增加 device.limit.#51
    // 插入 : 插入到 key 為 60 的 entry 之前 (#60)
    // 路徑 : "device.limit.#51"
    // 使用初始值.
    path1 = "device.limit.#51";
    DMSG("[add-entry] %s", path1);
    if(mcm_lulib_add_entry(&self_lulib, path1, "#60", NULL, 0) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_add_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_del_entry
刪除一筆 entry.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 刪除 device.vap.@1
    // 路徑 : "device.vap.@1"
    path1 = "device.vap.@1";
    DMSG("[del-entry] %s", path1);
    if(mcm_lulib_del_entry(&self_lulib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_del_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 刪除 device.vap.#15.station.@2
    // 路徑 : "device.vap.#15.station.@2"
    path1 = "device.vap.#15.station.@2";
    DMSG("[del-entry] %s", path1);
    if(mcm_lulib_del_entry(&self_lulib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_del_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_check_exist
檢查 entry 是否存在.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
MCM_DTYPE_BOOL_TD *
exist_buf
紀錄 entry 是否存在的緩衝
回傳值 :
0 : 不存在
1 : 有存在
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.
02.  entry 是否存在要看 exist_buf 的值.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_BOOL_TD is_exist;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 範例 : 檢查 device.syatem 是否存在 (因為是 gs 類型, 所以一定存在).
    // 路徑 : "device.system"
    path1 = "device.system";
    if(mcm_lulib_check_exist(&self_lulib, path1, &is_exist) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_check_exist(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[check-exist] %s = " MCM_DTYPE_BOOL_PF, path1, is_exist);

    // 範例 : 檢查 device.vap.@2 是否存在.
    // 路徑 : "device.vap.@2"
    path1 = "device.vap.@2";
    if(mcm_lulib_check_exist(&self_lulib, path1, &is_exist) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_check_exist(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[check-exist] %s = " MCM_DTYPE_BOOL_PF, path1, is_exist);

    // 範例 : 檢查 device.vap.#8.station.#1234 是否存在.
    // 路徑 : "device.vap.#8.station.#1234"
    path1 = "device.vap.#8.station.#1234";
    if(mcm_lulib_check_exist(&self_lulib, path1, &is_exist) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_check_exist(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[check-exist] %s = " MCM_DTYPE_BOOL_PF, path1, is_exist);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_get_all_key
讀取所有 entry 的 key 值.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
MCM_DTYPE_EK_TD **
key_buf
紀錄 key 列表的變數的緩衝
內部函式會配置記憶體空間並放入資料, 使用完需要釋放, 傳入參數需要做強制轉型 (MCM_DTYPE_EK_TD **)
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.
02.  使用 index 模式和 key 模式的資料搜索的速度 :
A.  知道所有 entry 的 key 值, 使用 key 模式的路徑.
B.  不知道所有 entry 的 key 值, 先使用此函式取得所有 entry 的 key 值, 再使用 key 模式的路徑.
C.  不知道所有 entry 的 key 值, 使用 index 模式的路徑.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1, path2[MCM_PATH_MAX_LENGTH];
    struct mcm_lulib_lib_t self_lulib;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_station_t station_v;
    MCM_DTYPE_EK_TD i, count, *key_array;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 範例 : 讀出 device.vap.* 所有的 key.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lulib_get_all_key(&self_lulib, path1, (MCM_DTYPE_EK_TD **) &key_array, &count)
                             < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_key(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);
    // 接著使用 key 值讀出所有的 device.vap.*
    for(i = 0; i < count; i++)
    {
        // 範例 : 設定 device.vap.*
        // 路徑 : "device.vap.*"
        // 型態 : struct mcm_dv_device_vap_t
        // 變數 : vap_v
        snprintf(path2, sizeof(path2), "device.vap.#%u", key_array[i]);
        if(mcm_lulib_get_entry(&self_lulib, path2, &vap_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lulib_get_entry(%s) fail", path2);
            goto FREE_02;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, vap_v.ekey);
        DMSG("[get-entry] %s.ssid = " MCM_DTYPE_S_PF, path2, vap_v.ssid);
        DMSG("[get-entry] %s.channel = " MCM_DTYPE_IUI_PF, path2, vap_v.channel);
    }
    free(key_array);

    // 範例 : 讀出 device.vap.@1.station.* 所有的 key.
    // 路徑 : "device.vap.@1.station.*"
    path1 = "device.vap.@1.station.*";
    if(mcm_lulib_get_all_key(&self_lulib, path1, (MCM_DTYPE_EK_TD **) &key_array, &count)
                             < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_key(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);
    // 接著使用 key 值讀出所有的 device.vap.@1.station.*
    for(i = 0; i < count; i++)
    {
        // 範例 : 讀出 device.vap.@1.station.*
        // 路徑 : "device.vap.@1.station.#{key}"
        // 類型 : struct mcm_dv_device_vap_station_t
        // 變數 : station_v
        snprintf(path2, sizeof(path2), "device.vap.@1.station.#%u", key_array[i]);
        if(mcm_lulib_get_entry(&self_lulib, path2, &station_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lulib_get_entry(%s) fail", path2);
            goto FREE_02;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, station_v.ekey);
        DMSG("[get-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path2, station_v.mac_addr);
        DMSG("[get-entry] %s.rule = " MCM_DTYPE_RK_PF, path2, station_v.rule);
    }
    free(key_array);

    // 範例 : 讀出 device.vap.#15.station.* 所有的 key.
    // 路徑 : "device.vap.#15.station.*"
    path1 = "device.vap.#15.station.*";
    if(mcm_lulib_get_all_key(&self_lulib, path1, (MCM_DTYPE_EK_TD **) &key_array, &count)
                             < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_key(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);
    // 接著使用 key 值讀出所有的 device.vap.#15.station.*
    for(i = 0; i < count; i++)
    {
        // 範例 : 讀出 device.vap.#15.station.*
        // 路徑 : "device.vap.#15.station.#{key}"
        // 類型 : struct mcm_dv_device_vap_station_t
        // 變數 : station_v
        snprintf(path2, sizeof(path2), "device.vap.#15.station.#%u", key_array[i]);
        if(mcm_lulib_get_entry(&self_lulib, path2, &station_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lulib_get_entry(%s) fail", path2);
            goto FREE_02;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, station_v.ekey);
        DMSG("[get-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path2, station_v.mac_addr);
        DMSG("[get-entry] %s.rule = " MCM_DTYPE_RK_PF, path2, station_v.rule);
    }
    free(key_array);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_get_all_entry
讀取所有 entry 的資料.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
void **
data_buf
紀錄資料的變數的緩衝 (變數的資料型態 [詳細])
內部函式會配置記憶體空間並放入資料, 使用完需要釋放, 傳入參數需要做強制轉型 (void **)
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1, path2[MCM_PATH_MAX_LENGTH];
    struct mcm_lulib_lib_t self_lulib;
    struct mcm_dv_device_t *device_v;
    struct mcm_dv_device_vap_t *vap_v;
    struct mcm_dv_device_vap_extra_t *extra_v;
    struct mcm_dv_device_vap_station_t *station_v;
    MCM_DTYPE_EK_TD i, count;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 對於 gd 類型的 group, 可以使用 index + key 模式.

    // 範例 : 讀出 device
    // 路徑 : "device"
    path1 = "device";
    if(mcm_lulib_get_all_entry(&self_lulib, path1, (void **) &device_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    DMSG("[get-all-entry] %s.descript = " MCM_DTYPE_S_PF, path1, device_v[0].descript);
    DMSG("[get-all-entry] %s.serial_number = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         device_v[0].serial_number[0], device_v[0].serial_number[1],
         device_v[0].serial_number[2], device_v[0].serial_number[3],
         device_v[0].serial_number[4], device_v[0].serial_number[5],
         device_v[0].serial_number[6], device_v[0].serial_number[7],
         device_v[0].serial_number[8], device_v[0].serial_number[9]);
    free(device_v);

    // 範例 : 讀出 device.vap.*
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lulib_get_all_entry(&self_lulib, path1, (void **) &vap_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    for(i = 0; i < count; i++)
    {
        snprintf(path2, sizeof(path2), "device.vap.@%u", i + 1);
        DMSG("[get-all-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, vap_v[i].ekey);
        DMSG("[get-all-entry] %s.ssid = " MCM_DTYPE_S_PF, path2, vap_v[i].ssid);
        DMSG("[get-all-entry] %s.channel = " MCM_DTYPE_IUI_PF, path2, vap_v[i].channel);
    }
    free(vap_v);

    // 範例 : 讀出 device.vap.@2.extra
    // 路徑 : "device.vap.@2.extra"
    path1 = "device.vap.@2.extra";
    if(mcm_lulib_get_all_entry(&self_lulib, path1, (void **) &extra_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    DMSG("[get-all-entry] %s.hidden = " MCM_DTYPE_ISC_PF, path1, extra_v[0].hidden);
    DMSG("[get-all-entry] %s.tx_power = " MCM_DTYPE_ISS_PF, path1, extra_v[0].tx_power);
    free(extra_v);

    // 範例 : 讀出 device.vap.#15.station.*
    // 路徑 : "device.vap.#15.station.*"
    path1 = "device.vap.#15.station.*";
    if(mcm_lulib_get_all_entry(&self_lulib, path1, (void **) &station_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    for(i = 0; i < count; i++)
    {
        snprintf(path2, sizeof(path2), "device.vap.#15.station.@%u", i + 1);
        DMSG("[get-all-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, station_v[i].ekey);
        DMSG("[get-all-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path2, station_v[i].mac_addr);
        DMSG("[get-all-entry] %s.rule = " MCM_DTYPE_RK_PF, path2, station_v[i].rule);
    }
    free(station_v);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_del_all_entry
刪除所有 entry.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 刪除所有的 device.vap.@1.station.*
    // 路徑 : "device.vap.@1.station.*"
    path1 = "device.vap.@1.station.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lulib_del_all_entry(&self_lulib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 刪除所有的 device.vap.#15.station.*
    // 路徑 : "device.vap.#15.station.*"
    path1 = "device.vap.#15.station.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lulib_del_all_entry(&self_lulib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 刪除所有的 device.limit.*
    // 路徑 : "device.limit.*"
    path1 = "device.limit.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lulib_del_all_entry(&self_lulib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_get_usable_key
取得可用的 key.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
MCM_DTYPE_EK_TD *
key_buf
紀錄可用的 key 的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.
02.  key_buf 返回的值大於 0 才表示有可用的 key.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_EK_TD key;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 要增加 entry 時, 需要不能重複的 key,
    // 如果不知道如何分配 key, 可用此函式取得可用的 key.

    // 範例 : 取得 device.vap.* 內可用的 key.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lulib_get_usable_key(&self_lulib, path1, &key) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_usable_key(%s) fail", path1);
        goto FREE_02;
    }
    if(key == 0)
    {
        DMSG("[usable-key] %s = entry is full", path1);
    }
    else
    {
        DMSG("[usable-key] %s = " MCM_DTYPE_EK_PF, path1, key);
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_run
執行 mint_cm/mcm_daemon/mcm_module 內的模組函式.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
char *
module_function
目標的函式名稱
void *
req_data_con
要傳給模組函式的資料
可為 NULL, 表示不傳送資料給模組函式
MCM_DTYPE_USIZE_TD
req_data_len
要傳給模組函式的資料的長度
若 req_data_con 是 NULL 則為 0
void **
rep_data_buf
紀錄模組函式回傳的資料的變數的緩衝
內部函式會配置記憶體空間並放入資料, 使用完需要釋放, 傳入參數需要做強制轉型 (void **)
可為 NULL, 表示不接收模組函式回傳的資料
MCM_DTYPE_USIZE_TD *
rep_data_len_buf
紀錄模組函式回傳的資料的長度的變數的緩衝
如果 rep_data_buf 是 NULL 則不會紀錄資料長度
可為 NULL, 表示不記錄資料長度
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  如果內部模組函式只需要讀取資料, 資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW, 如果內部模組函式需要修改資料, 資料存取模必須是 MCM_SPERMISSION_RW.
02.  因為內部模組函式的內容是客制化的, 所以需要的堆疊空間不固定 (區域變數的多寡和函式呼叫的層數都會影響需要的堆疊空間), 透過 session_stack_size 調整伺服器端處理此連線的執行緒的堆疊空間.
03.  和內部模組函式的資料傳遞的用法會在 #05-01#, #05-02# 說明.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 1048576;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 範例 : 執行 mcm_module_user_test_01 此函式.
    path1 = "mcm_module_user_test_01";
    DMSG("[run] %s", path1);
    if(mcm_lulib_run(&self_lulib, path1, NULL, 0, NULL, NULL) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_run(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

模組部分 :
這部分程式要放在 mint_cm/mcm_daemon/mcm_module 之下, 檔案名稱隨意 (*.c),
之後在 mint_cm 使用 make all 重新編譯.

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_control.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_debug.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "../mcm_service_handle_define.h"
#include "../mcm_config_handle_extern.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int mcm_module_user_test_01(
    struct mcm_service_session_t *this_session)
{
    srand(time(NULL));

    DMSG("module-%u", rand());

    return MCM_RCODE_PASS;
}

mcm_lulib_update
要求 mcm_daemon 做資料更新.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

此功能只有在特殊情況才需要.

程式修改資料時, mcm_daemon 的大致處理步驟 :
01.  程式呼叫 mcm_lulib_init() 取得使用權.
02.  程式修改資料.
03.  mcm_daemon 會把修改的資料放到資料庫的新進資料區 (原始的資料是放在資料庫的系統資料區).
04.  程式呼叫內部模組處理修改的資料.
05.  程式使用完畢, 呼叫 mcm_lulib_exit() 釋放使用權.
06.  mcm_daemon 根據最後一次的執行結果決定如何處理修改的資料.
成功: 將所做的修改套用回資料庫.
失敗: 放棄所做的修改.

如果在 [02] 時候做刪除資料, 接著在 [04] 之後讀取被刪除的資料, 照理說應該要讀不到資料, 但是因為資料在 [06] 才會套用回系統資料區, 所以實際上是能夠讀到資料的, 此函式就是要求 mcm_daemon 馬上做 [06] 的處理, 避免發生此問題.

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1;
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_EK_TD count;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    // 範例 :
    // 1. 刪除 device.limit.* 所有資料.
    // 2. 取得 device.limit.* 的資料筆數, 應該要是 0, 但是資料庫尚未更新,
    //    這時還是讀的到資料.
    // 3. 更新資料庫.
    // 4. 取得 device.limit.* 的資料筆數, 這時就會是 0.

    // 1. 刪除所有的 device.limit.*
    path1 = "device.limit.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lulib_del_all_entry(&self_lulib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 2. 取得 device.limit.* 的資料筆數, 應該要是 0, 但是資料庫尚未更新,
    //    這時還是讀的到資料.
    path1 = "device.limit.*";
    if(mcm_lulib_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count (before)] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 3. 更新資料庫.
    DMSG("[update]");
    if(mcm_lulib_update(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_update() fail");
        goto FREE_02;
    }

    // 4. 取得 device.limit.* 的資料筆數, 這時就會是是 0.
    path1 = "device.limit.*";
    if(mcm_lulib_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count (after)] %s = " MCM_DTYPE_EK_PF, path1, count);

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_save
要求 mcm_daemon 儲存資料到資料現在值檔案.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
MCM_DTYPE_BOOL_TD
force_save
是否強制要求儲存資料
0 : 否, 有需要儲存的資料被修改才儲存
1 : 是, 不論有無修改都要儲存
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    struct mcm_lulib_lib_t self_lulib;
    MCM_DTYPE_BOOL_TD force_save = 1;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    DMSG("[save] %s", force_save == 0 ? "check" : "force");
    if(mcm_lulib_save(&self_lulib, force_save) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_save() fail");
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}

mcm_lulib_shutdown
關閉 mcm_daemon, 當系統需要關機或重開機時先讓 mcm_daemon 正常關閉.
參數 說明
struct mcm_lulib_lib_t *
this_lulib
紀錄 mcm_lulib_api 所需要的資料
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  使用後並不會馬上關閉, 要等到 mcm_lulib_exit() 之後才會關閉.

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    struct mcm_lulib_lib_t self_lulib;

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RW;
    self_lulib.session_stack_size = 0;
    if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_init() fail");
        goto FREE_01;
    }

    DMSG("[shutdown]");
    if(mcm_lulib_shutdown(&self_lulib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_shutdown() fail");
        goto FREE_02;
    }

FREE_02:
    mcm_lulib_exit(&self_lulib);
FREE_01:
    return 0;
}


函式的混合使用

在實際情況下, 函式需要混合使用來完成工作, 這邊說明如何使用以及使用的時機.

方便說明, 左邊的函式使用右邊的簡稱 :
mcm_lulib_get_count get
mcm_lulib_get_alone
mcm_lulib_get_entry
mcm_lulib_get_all_entry
mcm_lulib_set_alone set
mcm_lulib_set_entry
mcm_lulib_add_entry add
mcm_lulib_del_entry del
mcm_lulib_delall_entry_value
mcm_lulib_run run

在取值的情況

使用的時機 :
要取得的資料必須先從系統中取出, 再放到資料庫中供讀取. [詳細]

使用方式 :
01.  使用 [run] 執行內部模組, 並在模組函式中實作將資料從系統中取出放到資料庫的部分.
02.  使用 [get] 取出資料.

範例 :
// 執行 module_get_loading(), 取得 device.system.loading
path1 = "module_get_loading";
mcm_lulib_run(&self_lulib, path1, NULL, 0, NULL, NULL);
path1 = "device.system.loading";
mcm_lulib_get_alone(&self_lulib, path1, &loading);

// 執行 mcm_module_get_client(), 取得 device.client.*
path1 = "mcm_module_get_client";
mcm_lulib_run(&self_lulib, path1, NULL, 0, NULL, NULL);
path1 = device.client.*;
mcm_lulib_get_all_entry(&self_lulib, path1, &client_v, &count);

...

注意事項 :
01.  可以使用多個 [run] 分別處理不同種類的資料, 也可以只使用一個 [run] 處理全部的資料.

在設值的情況

使用的時機 :
資料送入資料庫後, 需要用這些資料對系統做實際的設定. [詳細]

使用方式 :
01.  使用 [set] [add] [del] 修改資料.
02.  使用 [run] 執行內部模組, 並在模組函式中實作將修改的資料套用到系統的部分.

範例程式 :
// 設定 device.system.ip_addr, 執行 module_config_sytem 實作.
path1 = "device.system.ip_addr";
mcm_lulib_set_alone(&self_lulib, path1, &ip_addr, sizeof(ip_addr));
path1 = "module_config_sytem";
mcm_lulib_run(&self_lulib, path1, NULL, 0, NULL, NULL);

// 設定 device.vap.@1, 執行 module_config_vap 實作.
path1 = "device.vap.@1";
mcm_lulib_set_entry(&self_lulib, path1, &vap_v, sizeof(vap_v));

// 刪除 device.vap.#15, 執行 module_config_vap 實作.
path1 = "device.vap.#15";
mcm_lulib_del_entry(&self_lulib, path1);

// 增加 device.vap.#55, 執行 module_config_vap 實作.
path1 = "device.vap.#55";
mcm_lulib_add_entry(&self_lulib, path1, NULL, &vap_v, sizeof(vap_v));

path1 = "module_config_vap";
mcm_lulib_run(&self_lulib, path1, NULL, 0, NULL, NULL);

...

注意事項 :
01.  可以使用多個 [run] 分別處理不同種類的資料, 也可以只使用一個 [run] 處理全部的資料.

後續的章節會說明在內部模組中如何存取資料.


封裝的函式

mcm_lulib_do_...
此類函式是 mcm_lulib_init, mcm_lulib_..., mcm_lulib_exit 的封裝, 如果只需要處理一件事情可使用此類函式.

mcm_lulib_do_get_max_count
等同 mcm_lulib_get_max_count
mcm_lulib_do_get_count
等同 mcm_lulib_get_count
mcm_lulib_do_get_alone
等同 mcm_lulib_get_alone
mcm_lulib_do_set_alone
等同 mcm_lulib_set_alone
mcm_lulib_do_get_entry
等同 mcm_lulib_get_entry
mcm_lulib_do_set_entry
等同 mcm_lulib_set_entry
mcm_lulib_do_add_entry
等同 mcm_lulib_add_entry
mcm_lulib_do_del_entry
等同 mcm_lulib_del_entry
mcm_lulib_do_check_exist
等同 mcm_lulib_check_exist
mcm_lulib_do_get_all_key
等同 mcm_lulib_get_all_key
mcm_lulib_do_get_all_entry
等同 mcm_lulib_get_all_entry
mcm_lulib_do_del_all_entry
等同 mcm_lulib_del_all_entry
mcm_lulib_do_get_usable_key
等同 mcm_lulib_get_usable_key
mcm_lulib_do_run
等同 mcm_lulib_run
mcm_lulib_do_update
等同 mcm_lulib_update
mcm_lulib_do_save
等同 mcm_lulib_save
mcm_lulib_do_shutdown
等同 mcm_lulib_shutdown

範例 :
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lulib/mcm_lulib_api.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int main(
    int argc,
    char **argv)
{
    char *path1, path2[MCM_PATH_MAX_LENGTH];
    struct mcm_lulib_lib_t self_lulib;
    struct mcm_dv_device_vap_t vap_v;
    MCM_DTYPE_EK_TD count, i;
    MCM_DTYPE_FD_TD loading;
    MCM_DTYPE_S_TD descript[MCM_BSIZE_DEVICE_DESCRIPT];

    self_lulib.socket_path = "@mintcm";
    self_lulib.call_from = MCM_CFROM_USER;
    self_lulib.session_permission = MCM_SPERMISSION_RO;
    self_lulib.session_stack_size = 0;

    // 範例 : 取得 device.limit.* 的資料筆數上限.
    path1 = "device.limit.*";
    if(mcm_lulib_do_get_max_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_max_count(%s) fail", path1);
        goto FREE_01;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 讀出 device.system.loading
    path1 = "device.system.loading";
    if(mcm_lulib_do_get_alone(&self_lulib, path1, &loading) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_alone(%s) fail", path1);
        goto FREE_01;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_FD_PF, path1, loading);

    // 做修改的動作, 先把資料存取模式改為 rw.
    self_lulib.session_permission = MCM_SPERMISSION_RW;

    // 範例 : 設定 device.descript
    path1 = "device.descript";
    snprintf(descript, sizeof(descript), "network-device-123");
    DMSG("[set-alone] %s = " MCM_DTYPE_S_PF, path1, descript);
    if(mcm_lulib_do_set_alone(&self_lulib, path1, descript, strlen(descript)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_set_alone(%s) fail", path1);
        goto FREE_01;
    }

    // 做完修改的動作, 可以把資料存取模式改為 ro.
    self_lulib.session_permission = MCM_SPERMISSION_RO;

    // 範例 : 取得 device.vap.* 的資料筆數.
    path1 = "device.vap.*";
    if(mcm_lulib_do_get_count(&self_lulib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lulib_get_max_count(%s) fail", path1);
        goto FREE_01;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 讀出每一筆 device.vap.*
    for(i = 0; i < count; i++)
    {
        snprintf(path2, sizeof(path2), "device.vap.@%u", i + 1);
        if(mcm_lulib_do_get_entry(&self_lulib, path2, &vap_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lulib_get_entry(%s) fail", path2);
            goto FREE_01;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, vap_v.ekey);
        DMSG("[get-entry] %s.ssid = " MCM_DTYPE_S_PF, path2, vap_v.ssid);
        DMSG("[get-entry] %s.channel = " MCM_DTYPE_IUI_PF, path2, vap_v.channel);
    }

    // 其他 mcm_lulib_do_xxxx() 函式.

FREE_01:
    return 0;
}



注意事項

如果函式回傳的值小於 MCM_RCODE_PASS 的話, mcm_daemon 會結束連線並啟動恢復資料的動作 [詳細][06], 在 mcm_lulib_init() 和 mcm_lulib_exit() 期間所做的資料修改 (設定/增加/刪除) 都會廢棄並還原到修改前的資料. (如果有使用 mcm_lulib_update() 的話, 在呼叫 mcm_lulib_update() 之前的資料會保留)


如果要透過修改設定資料檔案來做讀取測試的話, 步驟 :
先關閉 mcm_daemon (有在執行的話), 修改設定值檔案, 重新執行 mcm_daemon.
修改設定值檔案有二個方法 :
初始值檔案
mcm_store_profile_default.txt
因為 mcm_daemon 會先讀取現在值檔案, 不存在才讀取初始值檔, 所以每次改好後執行 mcm_daemon 之前要先將現在值檔案刪除.
檔案內容格式 [詳細]
現在值檔案
mcm_store_profile_current.txt
檔案內容格式和初始值檔案相同 [詳細]

使用 [set] [add] [del] [delall] 操作後, 只要該 group 在資料模型中的 $(save) 為 1, 資料就會在 mcm_lulib_exit() 後寫回現在值的檔案, 所以除了使用列印的方式觀察之外也可以直接看檔案內容.


範例程式的使用

01.  範例程式目錄在 mint_cm/usage/example/0302.


02.  下面關於 make 的操作沒有特別註明的話都是在 mint_cm 目錄.


03.  第一次使用, 使用 make example_add KEY=0302 載入範例並編譯.


04.  user_app/user_app_0302 是範例程式,
必須先在目錄內使用 make all 進行編譯.

使用方式 :
user_app_0302 <test_item>
<test_item> 列表 :
max-count mcm_lulib_get_max_count() 範例
count mcm_lulib_get_count() 範例
get-alone mcm_lulib_get_alone() 範例
set-alone mcm_lulib_set_alone() 範例
get-entry mcm_lulib_get_entry() 範例
set-entry mcm_lulib_set_entry() 範例
check-exist mcm_lulib_check_exist() 範例
add-entry mcm_lulib_add_entry() 範例
del-entry mcm_lulib_del_entry() 範例
get-all-key mcm_lulib_get_all_key() 範例
get-all-entry mcm_lulib_get_all_entry() 範例
del-all-entry mcm_lulib_del_all_entry() 範例
run mcm_lulib_run() 範例
update-store mcm_lulib_update() 範例
shutdown mcm_lulib_shutdown() 範例


05.  先執行 mcm_daemon, 才可以使用 user_app_0302 做測試.


06.  測試完畢不使用後, 使用 make example_del KEY=0302 將範例移除.


07.  範例程式目錄下的檔案在做完 make example_add 後會複製到真正使用的位置, 要修改做測試的話要改在複製後的.
來源 profile/mcm_data_profile_0302.xml
目地 mint_cm/mcm_build/mcm_data_profile.xml
資料模型範例
有修改要使用 make all 重新編譯
來源 profile/mcm_store_profile_default_0302.txt
目地 mint_cm/mcm_build/mcm_store_profile_default.txt
資料預設值範例
使用 make all 後會再複製到 mint_cm/run
來源 module/mcm_module_0302.c
目地 mint_cm/mcm_daemon/mcm_module
搭配 mcm_lulib_run() 使用的內部模組範例
有修改要使用 make all 重新編譯