chapter 03-05

資料的存取 (指令部分)

此章節說明在 Shell Script 中如何使用提供的指令程式存取資料.


指令程式的檔案在 mint_cm/mcm_command/mcm.

指令程式預設是使用靜態連結的方式使用 MintCM 函式庫, 實際使用可以改用動態連結的方式.
USE_STATIC_MCM_LIB
(mint_cm/Makefile)
YES 使用靜態鏈結
NO 使用動態鏈結


指令程式參數的說明

指令程式需要的參數 :
<-a $(socket_path)>
伺服器的位址路徑. [詳細]
<-p $(session_permission)>
表示資料存取的模式.
ro 唯讀
rw 讀寫
[-s $(session_stack_size)]
伺服器端負責此連線的執行緒的堆疊大小. [詳細]
此參數非必須, 不輸入會使用 0.
<command_list ...>
要處理的指令串, 每個指令用空白分隔, 會依序處理這些指令, 指令格式會在後面說明.
<command1> <command2> ... <commandN>


變數格式的說明

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


mask_path
[詳細]
用途 :
01.  取得資料筆數上限, 也就是資料模型中的 $(max) 值. (maxcount)


mix_path
[詳細]
用途 :
01.  取得目前的資料筆數. (count)
02.  刪除資料. (delall)
03.  取得可用的 key. (usablekey)


full_path
[詳細]
用途 :
01.  讀取資料. (get)
02.  寫入資料. (set)
03.  增加資料. (add)
04.  刪除資料. (del)

insert_path
[詳細]
用途 :
01.  增加資料時指定要插入到哪個 entry 之前. (add)


指令串的格式

指令的格式為 :
$(operate_type)[.$(path)][=$(value)]

$(operate_type) 指令的操作類型
$(path) 要處理的資料的路徑
$(value) 要處理的資料

下面說明每種操作類型的用法.

maxcount
取得資料筆數上限, 也就是資料模型中的 $(max) 值.

格式 :
maxcount.$(mask_path)

$(mask_path) 目標的路徑 [詳細]

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

範例 :
# 讀出 device.system 的資料筆數上限.
./mcm -a @mintcm -p ro -s 0 maxcount.device.system

# 讀出 device.vap.* 的資料筆數上限.
./mcm -a @mintcm -p ro -s 0 maxcount.device.vap.*

# 讀出 device.vap.*.station.* 的資料筆數上限.
./mcm -a @mintcm -p ro -s 0 maxcount.device.vap.*.station.*


範例 :
#!/bin/bash

# 讀出 device.system 的資料筆數上限.
path="device.system"
max_count=`./mcm -a @mintcm -p ro -s 0 maxcount.${path}`
echo "${path} max count = ${max_count}"

# 讀出 device.vap.* 的資料筆數上限.
path="device.vap.*"
max_count=`./mcm -a @mintcm -p ro -s 0 maxcount.${path}`
echo "${path} max count = ${max_count}"

# 讀出 device.vap.*.station.* 的資料筆數上限.
path="device.vap.*.station.*"
max_count=`./mcm -a @mintcm -p ro -s 0 maxcount.${path}`
echo "${path} max count = ${max_count}"

count
取得目前的資料筆數.

格式 :
count.$(mix_path)

$(mix_path) 目標的路徑 [詳細]
[index / key 模式]

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

範例 :
# 取得 device 目前的資料筆數.
./mcm -a @mintcm -p ro count.device

# 取得 device.limit.* 目前的資料筆數.
./mcm -a @mintcm -p ro count.device.limit.*

# 取得 device.vap.@3.station.* 目前的資料筆數.
./mcm -a @mintcm -p ro count.device.vap.@3.station.*

# 取得 device.vap.#15.station.* 目前的資料筆數.
./mcm -a @mintcm -p ro count.device.vap.#15.station.*


範例 :
#!/bin/bash

# 取得 device 目前的資料筆數.
path="device"
count=`./mcm -a @mintcm -p ro count.${path}`
echo "${path} count = ${count}"

# 取得 device.limit.* 目前的資料筆數.
path="device.limit.*"
count=`./mcm -a @mintcm -p ro count.${path}`
echo "${path} count = ${count}"

# 取得 device.vap.* 底下所有的 station 目前的資料筆數.
path1="device.vap.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.vap.@${index1}.station.*"
    count2=`./mcm -a @mintcm -p ro count.${path2}`
    echo "${path2} count = ${count2}"
done

get
讀出 member 的資料.

格式 :
get.$(full_path)

$(full_path) 目標的路徑 [詳細]
[member 格式][index / key 模式]

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

範例 :
# 讀出 device.descript 的資料.
./mcm -a @mintcm -p ro get.device.descript

# 讀出 device.vap.@1.extra.tx_power 的資料.
./mcm -a @mintcm -p ro get.device.vap.@1.extra.tx_power

# 讀出 device.vap.#15.station.#33.mac_addr 的資料.
./mcm -a @mintcm -p ro get.device.vap.#15.station.#33.mac_addr


範例 :
#!/bin/bash

# 讀出 device.serial_number 的資料.
path="device.serial_number"
value=`./mcm -a @mintcm -p ro get.${path}`
echo "${path} = ${value}"

# 讀出 device.limit.*.priority 的資料.
path1="device.limit.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.limit.@${index1}.priority"
    value2=`./mcm -a @mintcm -p ro get.${path2}`
    echo "${path2} = ${value2}"
done

# 讀出 device.vap.*.station.*.mac_addr 的資料 (使用 key 模式).
path1="device.vap.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.vap.@${index1}.ekey"
    key2=`./mcm -a @mintcm -p ro get.${path2}`

    path2="device.vap.#${key2}.station.*"
    count2=`./mcm -a @mintcm -p ro count.${path2}`
    for ((index2 = 1; index2 <= count2; index2++))
    do
        path3="device.vap.#${key2}.station.@${index2}.mac_addr"
        value3=`./mcm -a @mintcm -p ro get.${path3}`
        echo "${path3} = ${value3}"
    done
done

set
寫入資料到 member.

格式 :
set.$(full_path)=$(value)

$(full_path) 目標的路徑 [詳細]
[member 格式][index / key 模式]

注意事項 :
01.  資料存取模式必須是 rw.
02.  字串類型和字節流類型的資料格式必須符合規定. [詳細]

範例 :
# 對 device.serial_number 寫入資料.
./mcm -a @mintcm -p rw set.device.serial_number=002C315f0b99cd

# 對 device.system.date 寫入資料 (空字串).
./mcm -a @mintcm -p rw set.device.system.date=

# 對 device.vap.#8.ssid 寫入資料.
./mcm -a @mintcm -p rw set.device.vap.#8.ssid=outside%20open

# 對 device.vap.@2.station.@1.rule 寫入資料.
./mcm -a @mintcm -p rw set.device.vap.@2.station.@1.rule=953

# 對 device.system.loading 和 device.limit.@1.name 和 device.vap.#23.extra.hidden 寫入資料.
./mcm -a @mintcm -p rw set.device.system.loading=-987.12345 set.device.limit.@1.name=rule-1 set.device.vap.#23.extra.hidden=1


範例 :
#!/bin/bash

# 對 device.serial_number 寫入資料.
path="device.serial_number"
value="002a1b3d1eF01500Aa"
result=`./mcm -a @mintcm -p rw set.${path}=${value}`

# 對 device.descript 和 device.system.ip_addr 和 device.system.loading 寫入資料.
path1="device.descript"
value1="Soho%20Router%25A"
path2="device.system.ip_addr"
value2=""
path3="device.system.loading"
value3="97.65403"
result=`./mcm -a @mintcm -p rw set.${path1}=${value1} set.${path2}=${value2} set.${path3}=${value3}`

# 對 device.vap.*.extra.tx_power 寫入資料 (使用 key 模式).
path1="device.vap.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.vap.@${index1}.ekey"
    key2=`./mcm -a @mintcm -p ro get.${path2}`

    path2="device.vap.#${key2}.extra.tx_power"
    value2=$((${index1} * 10))
    result=`./mcm -a @mintcm -p rw set.${path2}=${value2}`
done

# 對 device.vap.*.station.*.mac_addr 和 device.vap.*.station.*.rule 寫入資料.
list=
path1="device.vap.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.vap.@${index1}.station.*"
    count2=`./mcm -a @mintcm -p ro count.${path2}`
    for ((index2 = 1; index2 <= count2; index2++))
    do
        path3="device.vap.@${index1}.station.@${index2}.mac_addr"
        value3="00:12:3a:4b:55:$(((${index1} * 10) + ${index2}))"
        list="${list} set.${path3}=${value3}"

        path3="device.vap.@${index1}.station.@${index2}.rule"
        value3=$(((${index1} * 10) + ${index2}))
        list="${list} set.${path3}=${value3}"
    done
done
if [ ! -z "${list}" ]; then
    result=`./mcm -a @mintcm -p rw ${list}`
fi

add
增加一筆 entry.

格式 :
add.$(full_path)=$(insert_path)

$(full_path) 目標的路徑 [詳細]
[entry 格式][index / key 模式]
$(insert_path) 要插入到何處的路徑 [詳細]
[index 模式] / [key 模式]

注意事項 :
01.  資料存取模式必須是 rw.
02.  路徑可以是 [indxe / key 模式], 但是最後一段要加入的目標必須是 [key 模式].
03.  增加的資料的 key 值不可和存在的資料的 key 相同, 否則會操作失敗.
04.  增加資料後要使用 set 替資料設值, 否則會使用資料模型中設定的初始值.
05.  增加多層資料時, 要逐層增加.

範例 :
# 增加 device.vap.#51, 插入到第 1 筆 entry 之前 (@1).
./mcm -a @mintcm -p rw add.device.vap.#51=@1

# 增加 add.device.limit.#20, 插入到 key 為 3 的 entry 之前 (#3), 並設定資料.
./mcm -a @mintcm -p rw add.device.limit.#20=#3 set.device.limit.#20.name=limit-20 set.device.limit.#20.priority=12

# 增加 device.vap.#76.station.#5 和 device.vap.#76.station.#7, 都放在串列尾端 (""), 逐層增加.
./mcm -a @mintcm -p rw add.device.vap.#76= add.device.vap.#76.station.#5= add.device.vap.#76.station.#7=


範例 :
#!/bin/bash

# 增加 device.limit.#70, 放在串列尾端 ("").
path="device.limit.#70"
result=`./mcm -a @mintcm -p rw add.${path}=`

# 增加 device.vap.#101, 插入到 key 為 15 的 entry 之前 (#15), 並設定資料.
list=
path1="device.vap.#101"
list="${list} add.${path1}=#15"
# 設定 ssid 資料.
path2="${path1}.ssid"
value2="psk-101"
list="${list} set.${path2}=${value2}"
# 設定 channel 資料.
path2="${path1}.channel"
value2="36"
list="${list} set.${path2}=${value2}"
# 設定 device.vap.*.extra 部分.
path1="${path1}.extra"
# 設定 hidden 資料.
path2="${path1}.hidden"
value2="1"
list="${list} set.${path2}=${value2}"
# 設定 tx_power 資料.
path2="${path1}.tx_power"
value2="123"
list="${list} set.${path2}=${value2}"
result=`./mcm -a @mintcm -p rw ${list}`

# 先增加 device.vap.#200, 插入到第 1 筆 entry 之前 (@1), 再增加 5 個 station.
path1="device.vap.#200"
result=`./mcm -a @mintcm -p rw add.${path1}=@1`
list=
count1="5"
for ((index1 = 1; index1 <= count1; index1++))
do
    # 增加 station, 每次增加都插入在第 1 筆之前 (@1).
    path2="${path1}.station.#${index1}"
    list="${list} add.${path2}=@1"

    # 設定 mac_addr 資料.
    path3="${path2}.mac_addr"
    value3="00:11:aa:22:bb:$((${index1} * 10))"
    list="${list} set.${path3}=${value3}"

    # 設定 rule 資料.
    path3="${path2}.rule"
    value3="$((${index1} * 22))"
    list="${list} set.${path3}=${value3}"
done
result=`./mcm -a @mintcm -p rw ${list}`

del
刪除一筆 entry.

格式 :
del.$(full_path)

$(full_path) 目標的路徑 [詳細]
[entry 格式][index / key 模式]

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

範例 :
# 刪除 device.limit.@1
./mcm -a @mintcm -p rw del.device.limit.@1

# 刪除 device.vap.#15.station.@1
./mcm -a @mintcm -p rw del.device.vap.#15.station.@1


範例 :
#!/bin/bash

# 刪除 device.limit.#6
./mcm -a @mintcm -p rw del.device.limit.#6

# 刪除 device.vap.* 底下所有的 station.
list=
path1="device.vap.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.vap.@${index1}.station.*"
    count2=`./mcm -a @mintcm -p ro count.${path2}`
    for ((index2 = 1; index2 <= count2; index2++))
    do
        path3="device.vap.@${index1}.station.@${index2}"
        list="${list} del.${path3}"
    done
done
if [ ! -z "${list}" ]; then
    result=`./mcm -a @mintcm -p rw ${list}`
fi

exist
檢查 entry 是否存在.

格式 :
exist.$(full_path)

$(full_path) 目標的路徑 [詳細]
[entry 格式][index / key 模式]

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

範例 :
# 檢查 device.limit.@1 是否存在.
./mcm -a @mintcm -p ro exist.device.limit.@1

# 檢查 device.vap.#15.station.#543 是否存在.
./mcm -a @mintcm -p ro exist.device.vap.#15.station.#543


範例 :
#!/bin/bash

# 檢查 device.system 是否存在 (因為是 gs 類型, 所以一定存在).
./mcm -a @mintcm -p ro exist.device.system

# 檢查 device.vap.* 的第 1 到 9 筆的資料是否存在.
for ((index1 = 1; index1 <= 9; index1++))
do
    path="device.vap.@${index1}"
    result=`./mcm -a @mintcm -p ro exist.${path}`
    echo "${path} = ${result}"
done

# 檢查 device.limit.* 中 key 為 1 到 9 的資料是否存在.
for ((index1 = 1; index1 <= 9; index1++))
do
    path="device.limit.#${index1}"
    result=`./mcm -a @mintcm -p ro exist.${path}`
    echo "${path} = ${result}"
done

delall
刪除所有 entry.

格式 :
delall.$(mix_path)

$(mix_path) 目標的路徑 [詳細]

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

範例 :
# 刪除所有的 device.limit.*
./mcm -a @mintcm -p rw delall.device.limit.*

# 刪除 device.vap.#15.* 底下所有的 station.
./mcm -a @mintcm -p rw delall.device.vap.#15.station.*


範例 :
#!/bin/bash

# 刪除所有的 device.limit.*
./mcm -a @mintcm -p rw delall.device.limit.*

# 刪除 device.vap.* 底下所有的 station.
list=
path1="device.vap.*"
count1=`./mcm -a @mintcm -p ro count.${path1}`
for ((index1 = 1; index1 <= count1; index1++))
do
    path2="device.vap.@${index1}.station.*"
    list="${list} delall.${path2}"
done
if [ ! -z "${list}" ]; then
    result=`./mcm -a @mintcm -p rw ${list}`
fi

usablekey
取得可用的 key.

格式 :
usablekey.$(mix_path)

$(mix_path) 目標的路徑 [詳細]

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

範例 :
# 取得 device.vap.* 內可用的 key.
./mcm -a @mintcm -p rw usablekey.device.vap.*

# 取得 device.vap.@2.station.* 內可用的 key.
./mcm -a @mintcm -p rw usablekey.device.vap.@2.station.*


範例 :
#!/bin/bash

# 在 device.limit.* 增加 10 筆資料.
list=
path1="device.limit.*"
count1="10"
count2="0"
for ((index1 = 1; index1 <= count1; index1++))
do
    # 取得可用的 key.
    key2=`./mcm -a @mintcm -p rw usablekey.${path1}`
    if [ ${key2} -ne 0 ]; then
        # 增加資料筆數.
        path2="device.limit.#${key2}"
        result=`./mcm -a @mintcm -p rw add.${path2}=`
        count2=$((${count2} + 1))
    else
        break
    fi
done
echo "add ${count2} entry in ${path1}"

run
執行 mint_cm/mcm_daemon/mcm_module 內的模組函式.

格式 :
run.$(module_function)

$(module_function) 目標的函式名稱

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

範例 :
# 執行模組函式 mcm_module_command_test_01().
./mcm -a @mintcm -p ro run.mcm_module_command_test_01

# 執行模組函式 mcm_module_command_test_02().
# mcm_module_command_test_02() 會回傳訊息, mcm 會顯示回傳的訊息.
./mcm -a @mintcm -p ro -s 1048576 run.mcm_module_command_test_02

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

#include 
#include 
#include 
#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_command_test_01(
    struct mcm_service_session_t *this_session)
{
    srand(time(NULL));

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

    return MCM_RCODE_PASS;
}

int mcm_module_command_test_02(
    struct mcm_service_session_t *this_session)
{
    int fret = MCM_RCODE_MODULE_INTERNAL_ERROR;
    MCM_DTYPE_USIZE_TD tmp_len;
    char *tmp_buf;

    // 回傳訊息給外部程式, 這部分的用法會在 05-02 說明.

    tmp_len = 256;
    tmp_buf = (char *) malloc(tmp_len);
    if(tmp_buf == NULL)
    {
        DMSG("call malloc() fail [%s]", strerror(errno));
        goto FREE_01;
    }

    snprintf(tmp_buf, tmp_len, "command-%u", rand());
    tmp_len = strlen(tmp_buf) + 1;

    this_session->rep_data_buf = tmp_buf;
    this_session->rep_data_len = tmp_len;

    fret = MCM_RCODE_PASS;
FREE_01:
    return fret;
}


範例 :
#!/bin/bash

# 設定 device.system.ip_addr 並執行 mcm_module_command_test_01().
list=
path="device.system.ip_addr"
value="192.168.111.222"
list="${list} set.${path}=${value}"
path="mcm_module_command_test_01"
list="${list} run.${path}"
result=`./mcm -a @mintcm -p rw ${list}`
if [ ! -z ${result} ]; then
    echo "${result}"
fi

# 設定 device.system.ip_addr 並執行 mcm_module_command_test_02().
list=
path="device.system.ip_addr"
value="192.168.222.111"
list="${list} set.${path}=${value}"
path="mcm_module_command_test_02"
list="${list} run.${path}"
result=`./mcm -a @mintcm -p rw ${list}`
if [ ! -z ${result} ]; then
    echo "${result}"
fi

update
要求 mcm_daemon 做資料更新. (需要使用的情況 [詳細])

格式 :
update


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

範例 :
# 更新 (單獨使用無實際作用, 只是說明指令用法).
./mcm -a @mintcm -p rw update


範例 :
#!/bin/bash

# 情況一.
# 刪除一筆 device.limit.*, 之後取得 device.limit.* 的資料筆數,
# 正常情況取出的資料筆數會少一筆, 但是實際上資料庫尚未更新,
# 所以資料筆數不會減少.
path1="device.limit.*"
# 先取得原本的資料筆數.
count1=`./mcm -a @mintcm -p ro count.${path1}`
# 刪除一筆資料後直接取得資料筆數.
path2="device.limit.@1"
count2=`./mcm -a @mintcm -p rw del.${path2} count.${path1}`
# 刪除前和刪除後的資料筆數會是一樣.
echo "[no update]"
echo "before delete, count = ${count1}"
echo "after delete,  count = ${count2}"

# 情況二.
# 刪除一筆 device.limit.*, 接著做更新, 再取得 device.limit.* 的資料筆數,
# 這時候取得資料筆數就會是正常的少一筆.
path1="device.limit.*"
# 先取得原本的資料筆數.
count1=`./mcm -a @mintcm -p ro count.${path1}`
# 刪除一筆資料後先更新再取得資料筆數.
path2="device.limit.@1"
count2=`./mcm -a @mintcm -p rw del.${path2} update count.${path1}`
# 刪除前和刪除後的資料筆數會是不一樣.
echo "[with update]"
echo "before delete, count = ${count1}"
echo "after delete,  count = ${count2}"

save
要求 mcm_daemon 儲存資料到資料現在值檔案.

格式 :
save=$(save_method)

$(save_method) 是否強制要求儲存資料
check : 否, 有需要儲存的資料被修改才儲存
force : 是, 不論有無修改都要儲存

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

範例 :
# 有需要儲存的資料被修改才儲存.
./mcm -a @mintcm -p rw save=check

# 強制儲存.
./mcm -a @mintcm -p rw save=force

shutdown
關閉 mcm_daemon.

格式 :
shutdown

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

範例 :
# 關閉.
./mcm -a @mintcm -p rw shutdown