天天看點

openwrt開發筆記三:uci移植及API調用

1.uci編譯安裝、移植

安裝依賴 libubox

#安裝cmake
sudo apt-get install cmake
#下載下傳依賴庫libubox
git clone http://git.nbd.name/luci2/libubox.git
git clone https://git.openwrt.org/project/libubox.git
#安裝libubox,先安裝到ubuntu同時制作一份安裝庫
cd libubox
mkdir build install
cd build
cmake .. -DBUILD_LUA=off -DBUILD_EXAMPLES=off
sudo make install
#ubuntu庫安裝完畢,開始制作目标庫
#删除build目錄所有檔案,指定交叉編譯工具和安裝目錄
sudo rm -rf *
cmake .. -DBUILD_LUA=off -DBUILD_EXAMPLES=off -DCMAKE_INSTALL_PREFIX=../install  -DCMAKE_C_COMPILER=/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi/bin/arm-openwrt-linux-gcc
#安裝到交叉編譯庫中
sudo rm -rf *
cmake .. -DBUILD_LUA=off -DBUILD_EXAMPLES=off -DCMAKE_INSTALL_PREFIX=/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi/usr  -DCMAKE_C_COMPILER=/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi/bin/arm-openwrt-linux-gcc

make install
           

安裝uci

#下載下傳uci源碼
git clone https://git.openwrt.org/project/uci.git
#安裝libubox,先安裝到ubuntu同時制作一份安裝庫
cd uci
mkdir build install
cd build
cmake .. -DBUILD_LUA=off
sudo make install
#ubuntu庫安裝完畢,開始制作目标庫
#删除build目錄所有檔案,指定交叉編譯工具和安裝目錄
sudo rm -rf *
cmake .. -DBUILD_LUA=off -DCMAKE_INSTALL_PREFIX=../install  -DCMAKE_C_COMPILER=/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi/bin/arm-openwrt-linux-gcc
#交叉編譯安裝到交叉編譯庫目錄
sudo rm -rf *
cmake .. -DBUILD_LUA=off -DCMAKE_INSTALL_PREFIX=/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi/usr  -DCMAKE_C_COMPILER=/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi/bin/arm-openwrt-linux-gcc
           

2.C調用uci

配置示例檔案 /etc/config/gateway

config interface 'netconf'
	option serverurl '10.99.20.33/gateway'
	option loaclip '192.168.11.3'
	option netmask '255.255.255.0'
	option gateway '192.168.11.1'
	option proto 'static'
	option dns '10.55.33.2'
	option serverip '10.99.20.100'
	option serverport '8000'

config device
	option devstate '0'
	option devid '001'
	option devtype '網關'
	option devmodel 'GW-001'
	option devposition '武漢'
	option enable 'yes'

config rs485
	option name 'COM1'
	option baudrate '9600'
	option databit '8'
	option stopbit '1'
	option parity 'n'
	option enable 'yes'

config device
	option devstate '0'
	option devid '002'
	option devtype '單燈控制器'
	option devmodel 'LIGHT-001'
	option devposition '武漢'
	option enable 'yes'

config device
	option devstate '0'
	option devid '003'
	option devtype '單燈控制器'
	option devmodel 'LIGHT-001'
	option devposition '武漢'
	option enable 'yes'
           

代碼示例

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "uci.h"
#include "config.h"

#define UCI_CONFIG_FILE "/etc/config/gateway"

/**
 * @brief 擷取配置資訊
 * @param  section	配置段名稱
 * @param  option 	配置項
 * @param  pdata  	擷取的配置内容
 * @param  plen  	擷取的配置内容長度
 * @return int 		成功傳回UCI_OK, 失敗傳回其它值
 */
int config_get(char *section, char *option, unsigned char *pdata, unsigned short *plen)
{
	int ret = UCI_OK;
	struct uci_package * pkg = NULL;
	const char *value;

	ctx = uci_alloc_context(); 	// 申請一個UCI上下文.
	if (!ctx) {
		return UCI_ERR_MEM;
	}

	ret = uci_load(ctx, UCI_CONFIG_FILE, &pkg);		// 加載并解析配置檔案
	if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        return ret;
    }

	struct uci_section *s = uci_lookup_section(ctx, pkg, section);
	if(s != NULL)
	{
		if (NULL != (value = uci_lookup_option_string(ctx, s, option)))
		{
//			pdata = (unsigned char *)strdup(value);
			strncpy(pdata, value, 100);
			*plen = strlen(pdata);
		}
		else
		{
			uci_unload(ctx, pkg);
			uci_free_context(ctx);
			ctx = NULL;
			return UCI_ERR_NOTFOUND;
		}
	}
	else
	{
		uci_unload(ctx, pkg);
		uci_free_context(ctx);
		ctx = NULL;
		return UCI_ERR_NOTFOUND;
	}

	uci_unload(ctx, pkg);
	uci_free_context(ctx);
	ctx = NULL;
	return ret;
}

/**
 * @brief 設定配置資訊
 * @param  section 	配置段名稱
 * @param  option  	配置項
 * @param  pdata  	擷取的配置内容
 * @param  plen    	擷取的配置内容長度
 * @return int		成功傳回UCI_OK, 失敗傳回其它值
 */
int config_set(char *section, char *option, unsigned char *pdata, unsigned short *plen)
{
	struct uci_package * pkg = NULL;
	struct uci_element *e;
	int ret = UCI_OK;

	ctx = uci_alloc_context();
	if (!ctx) {
		return UCI_ERR_MEM;
	}

	struct uci_ptr ptr ={
				.package = "gateway",
				.section = section,
				.option = option,
				.value = pdata,
			};

	ret = uci_set(ctx, &ptr);	//寫入配置
    if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        return ret;
    }

	ret = uci_save(ctx, ptr.p);	//儲存更改
    if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        return ret;
    }

    ret = uci_commit(ctx, &ptr.p, false);	//送出更改
    if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        return ret;
    }

	// system("/etc/init.d/network restart");	//配置應用示例

	uci_free_context(ctx);
    return ret;
}

/**
 * @brief 擷取配置項值
 * @param  o      	配置項
 * @param  out   	擷取的配置内容
 * @return int		成功傳回UCI_OK, 失敗傳回其它值
 */
static int uci_get_value(struct uci_option *o, char *out)
{
	struct uci_element *e;
    const char *delimiter = " ";	//值為清單時的分隔符
	bool sep = false;

	switch(o->type) {
	case UCI_TYPE_STRING:
        strcpy(out, o->v.string);
		break;
	case UCI_TYPE_LIST:
		uci_foreach_element(&o->v.list, e) {
            if(sep)
                strcat(out, delimiter);
            strcat(out, e->name);
			sep = true;
		}
		break;
	default:
		return UCI_ERR_INVAL;
		break;
	}

    return UCI_OK;
}

/**
 * @brief 擷取uci配置項
 * @param  arg	擷取該參數下的值
 *         eg: gateway.@interface[0]
 *             gateway.interface0.serverport
 * @param  out	擷取的值存儲區
 * @return int 	成功傳回UCI_OK, 失敗傳回其它值
 */
int uci_get_str(const char *arg, char *out)
{
    struct uci_context *ctx;
    struct uci_element *e;
	struct uci_ptr ptr;
	int ret = UCI_OK;
    char *name = NULL;

    if(arg == NULL || out == NULL) return UCI_ERR_INVAL;
    name = strdup(arg);
    if(name == NULL) return UCI_ERR_INVAL;

    ctx = uci_alloc_context();
	if (!ctx) {
        free(name);
		return UCI_ERR_MEM;
	}

    if (uci_lookup_ptr(ctx, &ptr, name, true) != UCI_OK) {
        uci_free_context(ctx);
        free(name);
		return UCI_ERR_NOTFOUND;
	}

    if(UCI_LOOKUP_COMPLETE & ptr.flags)
    {
        e = ptr.last;
        switch(e->type)
        {
            case UCI_TYPE_SECTION:
                ret = UCI_ERR_INVAL;
            break;
            case UCI_TYPE_OPTION:
                ret = uci_get_value(ptr.o, out);
            break;
            default:
                ret = UCI_ERR_NOTFOUND;
            break;
        }
    }
    else
        ret = UCI_ERR_NOTFOUND;

    uci_free_context(ctx);
    free(name);
    return ret;
}

/**
 * @brief 設定uci配置項 , 儲存并且送出更改到檔案
 * @param  arg	設定參數
 *         eg: gateway.@interface[0]=wifi-iface
 *             gateway.interface0.serverip=10.99.20.100
 *             gateway.interface0.serverport=8000
 * @return int 	成功傳回UCI_OK, 失敗傳回其它值
 */
int uci_set_str(const char *arg)
{
    struct uci_context *ctx;
    struct uci_element *e;
	struct uci_ptr ptr;
	int ret = UCI_OK;
    char *name = NULL;

    if(arg == NULL) return UCI_ERR_INVAL;
    name = strdup(arg);
    if(name == NULL) return UCI_ERR_MEM;

    ctx = uci_alloc_context();
	if (!ctx) {
        free(name);
		return UCI_ERR_MEM;
	}

    if (uci_lookup_ptr(ctx, &ptr, name, true) != UCI_OK) {
        uci_free_context(ctx);
        free(name);
		return UCI_ERR_NOTFOUND;
	}

    ret = uci_set(ctx, &ptr);
    if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        free(name);
        return ret;
    }

    ret = uci_save(ctx, ptr.p);
    if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        free(name);
        return ret;
    }

    ret = uci_commit(ctx, &ptr.p, false);
    if(ret != UCI_OK)
    {
        uci_free_context(ctx);
        free(name);
        return ret;
    }

    uci_free_context(ctx);
    free(name);
    return ret;
}

           

測試用例 config_test.c

int main(void)
{
    printf("Hello World!\n");
    char tmp[100];
    unsigned short tmplen;
    int rc = config_get("netconf", "serverip", tmp, &tmplen);
    printf("serverip is %s --%d --%d\n", tmp,  tmplen, rc);

    rc = config_get("netconf", "serverport", tmp, &tmplen);
	printf("serverport is %s --%d --%d\n", tmp, tmplen, rc);

	rc = config_set("netconf", "serverport", "8000", &tmplen);
	printf("serverport set --%d\n", rc);

	rc = config_get("netconf", "serverport", tmp, &tmplen);
	printf("serverport is %s --%d --%d\n", tmp, tmplen, rc);

    rc =  uci_get_str("gateway.netconf.serverport", tmp);
    printf("serverport is %s --%d\n", tmp,  rc);

    rc =  uci_set_str("gateway.netconf.serverport=9000");
    printf("serverport set --%d\n", rc);

    rc =  uci_get_str("gateway.netconf.serverport", tmp);
    printf("serverport is %s --%d\n", tmp,  rc);

    return 0;
}
           

用例 Makefile

TOOLCHAIN_DIR = "/home/wangh/workspace/openwrt/PandoraBox-SDK-qualcomm-ipq40xx_gcc-4.9-linaro_uClibc-1.0.x_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-4.9-linaro_uClibc-1.0.x_eabi"

BIN := config_test
OBJS := config_test.o
OBJS += config.o

all:$(OBJS) $(BIN) 

$(OBJS):%.o:%.c
	$(CC) $(CFLAGS) -I $(TOOLCHAIN_DIR)/usr/include/ -c $^ -o $@

$(BIN):$(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS) -L $(TOOLCHAIN_DIR)/usr/lib -luci

clean: 
	rm -f *.o $(BIN)
           

3.lua調用uci

#!usr/bin/lua
require("uci")

-- uci測試
x = uci.cursor() --uci上下文
local serverip = x:get("gateway", "netconf", "serverip")
print(serverip)

x:foreach(
	"gateway",
	"device",
	function(s)
		if s.devid == "002" then
			print("------------------")
			for key, value in pairs(s) do
				print(key .. ": " .. tostring(value))
			end
		end
	end
)