第9章 OpenWrt-UCI的使用(二)

第9章 OpenWrt-UCI的使用(二)

本章主要讲述了UCI API的使用,关于UCI指令的使用请参考上一篇文章《OpenWrt-UCI的使用(一)》

UCI API 编程接口

UCI接口都是以小写的uci开头并放在uci.h头文件中。大多数函数的第一个参数均为uci_context的指针变量。这个变量在程序初始化时调用uci_alloc_context函数分配空间并设置初始值。通过调用uci_free_context函数释放该空间。

首先介绍一下会用到的结构体:

  • uci上下文结构体:
struct uci_context
{
    /* 配置文件包列表 */
    struct uci_list root;
 
    /* 解析上下文,只用于错误处理 */
    struct uci_parse_context *pctx;
 
    /* 后端导入导出 */
    struct uci_backend *backend;
    struct uci_list backends;
 
    /* uci 运行标识 */
    enum uci_flags flags;
 
    char *confdir;
    char *savedir;
 
    /* search path for delta files */
    struct uci_list delta_path;
 
    /* 私有数据 */
    int err;
    const char *func;
    jmp_buf trap;
    bool internal, nested;
    char *buf;
    int bufsz;
};
  • 配置文件(package)对应的结构体:
struct uci_package
 
{
 
    struct uci_element e;
 
    struct uci_list sections;
 
    struct uci_context *ctx;
 
    bool has_delta;
 
    char *path;
 
    /* private: */
 
    struct uci_backend *backend;
 
    void *priv;
 
    int n_section;
 
    struct uci_list delta;
 
    struct uci_list saved_delta;
 
};
  • 节(section)对应的结构体:
struct uci_section
{
    struct uci_element e;
    struct uci_list options;
    struct uci_package *package;
    bool anonymous;
    char *type;
};
  • 元素位置指针结构体
struct uci_ptr
{
    enum uci_type target;
    enum {
        UCI_LOOKUP_DONE =    (1 << 0),
        UCI_LOOKUP_COMPLETE = (1 << 1),
        UCI_LOOKUP_EXTENDED = (1 << 2),
    } flags;
 
    struct uci_package *p;
    struct uci_section *s;
    struct uci_option *o;
    struct uci_element *last;
 
    const char *package;
    const char *section;
    const char *option;
    const char *value;
};

常用的函数如下,可以参考uci.h文件来查看下表。

函数含义
uci_alloc_context分配UCI上下文环境对象
uci_free_context释放UCI上下文环境对象
uci_load解析UCI配置文件,并存储到UCI对象中。@name:配置文件名,相对于配置目录,@package:在这个变量中存储装载的配置包
uci_unload从UCI上下文环境对象中unload配置文件
uci_loop_ptr分割字符串并查找
uci_set设置元素值,更新或创建的元素将存储在ptr->last中
uci_add_list向list中增加一个元素值
uci_delete删除一个元素,配置节或者选项
uci_save保存一个package修改的delta
uci_commit提交更新到package文件
uci_set_confdir修改UCI配置文件的存储位置,默认为/etc/config

快速使用示例1

如下代码

目录结构如下:

atlas@atlas-virtual-machine:$ cd package/utils/uci_api_demo/
atlas@atlas-virtual-machine:$ ls
files  Makefile  src
atlas@atlas-virtual-machine:$ tree 
.
├── files
│   └── uci_api_demo.conf
├── Makefile
└── src
    ├── Makefile
    └── uci_api_demo.c

2 directories, 4 files

我们创建了一个名为“uci_api_demo.conf”的配置文件,内容如下,ipk安装到OpenWrt后,该文件会对应成“/etc/config/uci_api_demo”。

config my_server web_server
	option ip '127.0.0.1'
	option port '8090'

"src/uci_api_demo.c”内容如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uci.h"
int main() 
{ 
    struct uci_context *context;
    struct uci_ptr ptr;
    char *str = strdup("uci_api_demo.web_server.ip"); 
 
    context = uci_alloc_context();
    if (UCI_OK != uci_lookup_ptr(context, &ptr, str, true)) {
        uci_perror(context, "no found!\n");
        return -1;
    }
 
    printf("%s\n", ptr.o->v.string);
    uci_free_context(context);
    free(str);

    return 0;
}

“src/Makefile”内容如下:

# CFLAGS +=
LDFLAGS += -luci    #依赖uci.so

uci_api_demo : uci_api_demo.o
	$(CC)  uci_api_demo.o $(LDFLAGS) -o uci_api_demo

uci_api_demo.o:uci_api_demo.c
	$(CC) $(CFLAGS) $(LDLIBS) -c uci_api_demo.c


clean:
	rm -rf *.o uci_api_demo

根目录的“Makefile”内容如下:

include $(TOPDIR)/rules.mk

PKG_NAME:=uci_api_demo
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

define Package/uci_api_demo
	SECTION:=utils
	CATEGORY:=Utilities
	DEPENDS:= +uci +libuci
	TITLE:=uci_api_demo --learn uci api
endef

define Package/uci_api_demo/description
	This is a uci api demo
endef

define Build/Prepare
	echo "Here is Build/Prepare"
	mkdir -p $(PKG_BUILD_DIR)
	$(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Package/uci_api_demo/install
	echo "Here is Package/install"
	$(INSTALL_DIR) $(1)/etc/config
	$(INSTALL_CONF) ./files/uci_api_demo.conf $(1)/etc/config/uci_api_demo
	$(INSTALL_DIR) $(1)/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/uci_api_demo $(1)/bin/
endef

$(eval $(call BuildPackage,uci_api_demo))

将源代码编程成ipk并完成安装(可参考《第3章 OpenWrt应用层ipk编写及编译》)。

从执行结果可以看到,可执行程序uci_api_demo读取到uci_api_demo这个配置文件中ip这个option的值

root@(none):~# cat /etc/config/uci_api_demo
config my_server web_server
        option ip '127.0.0.1'
        option port '8090'

root@(none):~# uci_api_demo
127.0.0.1
root@(none):~#

快速使用示例2

目录结构如下,

atlas@atlas-virtual-machine:$ cd package/utils/uci_api_demo_2/
atlas@atlas-virtual-machine:$ tree 
.
├── files
│   └── uci_api_demo.conf
├── include
│   └── uci_utils.h
├── Makefile
└── src
    ├── Makefile
    ├── uci_api_demo.c
    └── uci_utils.c

3 directories, 6 files
atlas@atlas-virtual-machine:$

“include/uci_utils.h”内容如下:

int set_uci(const char *package, const char *section, const char *option, const char *value);
int resolve_uci(const char *package);

“src/uci_utils.c”内容如下:

#include <string.h>

#include "uci_utils.h"
#include "uci.h"

int set_uci(const char *package, const char *section, const char *option, const char *value)
{
    struct uci_ptr ptr;
    memset(&ptr, 0, sizeof(ptr));

    struct uci_context * _ctx = uci_alloc_context(); //申请上下文
    if (UCI_OK != uci_load(_ctx, package, &ptr.p)) {
        printf("open set_uci UCI_CONFIG_FILE fail exit\n");
        goto set_cleanup; //如果打开UCI文件失败,则跳到末尾 清理 UCI 上下文. 
    }

    ptr.package = "config";
    ptr.section = section;
    ptr.option = option;
    ptr.value = value;

    uci_set(_ctx, &ptr); //写入配置 

    uci_commit(_ctx, &ptr.p, false); //提交保存更改

    uci_unload(_ctx, ptr.p); //卸载包

set_cleanup:

    //printf("uci set_uci exit\n");

    uci_free_context(_ctx);  //释放上下文

    return 0;
}


int resolve_uci(const char *package)
{
    int rc = -1;
    struct uci_package * pkg = NULL;
    struct uci_element *e, *e1;
       struct uci_ptr ptr;
    char *value = NULL;
       struct uci_option *o;

    struct uci_context *ctx = uci_alloc_context(); // 申请一个UCI>上下文.

    if (UCI_OK != uci_load(ctx, package, &pkg)) {
        printf("open file UCI_CONFIG_FILE fail exit\n");
        goto cleanup; //如果打开UCI文件失败,则跳到末尾 清理 UCI 上下文. 
    }

    /*遍历UCI的每一个节*/
    uci_foreach_element(&pkg->sections, e) {
        struct uci_section *s = uci_to_section(e); 
        // 此时通过 s->e.name 来获取.
	printf("---- section name: %s ---- \n", s->e.name);
		uci_foreach_element(&s->options, e1) {
			o = uci_to_option(e1);
			printf("   --- option name: %s --, value: %s \n", o->e.name, o->v.string);
		}
	}

cleanup:
    uci_free_context(ctx);
    ctx = NULL;

    return 0;
}

“src/uci_api_demo.c”内容如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uci_utils.h"

int main() 
{ 
	const char *pkg_file = "/etc/config/uci_api_demo";
	const char *sec_name = "web_server";
	const char *opt_type = "backup_port";
	const char *opt_value = "8888";
	printf("---- before change ----");
    	resolve_uci(pkg_file);
	printf("---- after change ----");
	set_uci(pkg_file, sec_name, opt_type, opt_value);
    	resolve_uci(pkg_file);
	return 0;
}

“src/Makefile”内容如下:

LDFLAGS += -luci -I./include

uci_api_demo_2 : uci_api_demo_2.o uci_utils.o
	$(CC)   $(LDFLAGS) uci_api_demo_2.o uci_utils.o -o uci_api_demo_2

uci_api_demo_2.o:uci_api_demo.c
	$(CC) $(CFLAGS) $(LDLIBS) $(LDFLAGS) -c uci_api_demo.c -o uci_api_demo_2.o

uci_utils.o:uci_utils.c
	$(CC) $(CFLAGS) $(LDLIBS) $(LDFLAGS) -c uci_utils.c

clean:
	rm -rf *.o uci_api_demo_2

“files/uci_api_demo.conf”内容如下:

config my_server web_server
	option ip '127.0.0.1'
	option port '8090'

将ipk编译并进行安装,测试结果如下:

root@(none):~# opkg install /tmp/uci_api_demo_2_1_i386_pentium4.ipk
Package uci_api_demo_2 (1) installed in root is up to date.
root@(none):~# opkg remove uci_api_demo_2
Removing package uci_api_demo_2 from root...
root@(none):~# opkg install /tmp/uci_api_demo_2_1_i386_pentium4.ipk
Installing uci_api_demo_2 (1) to root...
Configuring uci_api_demo_2.
root@(none):~#
root@(none):~# uci_api_demo_2
---- before change -------- section name: web_server ----
   --- option name: ip --, value: 127.0.0.1
   --- option name: port --, value: 8090
---- after change -------- section name: web_server ----
   --- option name: ip --, value: 127.0.0.1
   --- option name: port --, value: 8090
   --- option name: backup_port --, value: 8888
root@(none):~# cat /etc/config/uci_api_demo

config my_server 'web_server'
        option ip '127.0.0.1'
        option port '8090'
        option backup_port '8888

点解连接阅读《OpenWrt-UCI的使用(一)》

微信关注《万物互联技术》获取更多内容

在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值