OpenWrt上UCI库的使用(C语言调用)

1 LUCI 配置文件简介

LUCI 的配置文件一般存储在 /etc/config 目录下。比如网络配置文件则是 /etc/config/network,无线的配置文件是 /etc/config/wireless。更多配置文件的含义参考官方 WIKI.

2 简单的基本关系

这里画一个图让大家大致了解配置文件的内容和 uci 的几个基本结构之间的对应关系。(例举文件为 uhttpd 的配置文件)
在这里插入图片描述

3 结构体介绍

  1. struct uci_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;
    };
    
  2. struct uci_section:节结构体,它对应配置文件中的节。

    struct uci_section
    {
        struct uci_element e;
        struct uci_list options;
        struct uci_package *package;
        bool anonymous;
        char *type;
    };
    
  3. struct uci_option:选项结构体,它对应配置文件里节中的 option 或者 list。

    struct uci_option
    {
        struct uci_element e;
        struct uci_section *section;
        enum uci_option_type type;
        union {
            struct uci_list list;
            char *string;
        } v;
    };
    
  4. struct uci_ptr:元素位置指针结构,用来查询并保存对应位置元素。

    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;
    };
    
  5. struct uci_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;
    };
    

4 部分API介绍

  1. uci_alloc_context:动态申请一个 uci 上下文结构。

    struct uci_context *uci_alloc_context(void);
    
  2. uci_free_contex:释放由 uci_alloc_context 申请的 uci 上下文结构且包括它的所有数据。

    void uci_free_context(struct uci_context *ctx);
    
  3. uci_lookup_ptr:由给定的元组查找元素。

    /**
    * uci_lookup_ptr: 分离一个uci元组字符串且查找对应元素树
    * @ctx: uci context结构体指针
    * @ptr: 存放元素查询结果的结构体指针
    * @str: 待查找的uci元组字符串
    * @extended: 允许扩展语法查询
    *
    * 如果extended被设为ture,则uci_lookup_ptr支持下列扩展语法:
    *
    * 例子:
    *  network.@interface[0].ifname ('ifname' option of the first interface section)
    *  network.@interface[-1]      (last interface section)
    * Note: 有必要的话uci_lookup_ptr将会自动加载配置文件包
    * @str 不能是一个const类型指针,它在使用的过程中将会被更改且用于将字符串填写到@ptr中,因此
    * 它只要@ptr还在使用,它就必须是可用的
    *
    * 这个函数在指定包元组的的字符串未被找到时返回UCI_ERR_NOTFOUND,否则返回UCI_OK
    *
    * 记住在查找其他部分失败的情况,如果它们同样被指定,包括section和option,同样会返回UCI_OK,
    * 但是ptr->flags * UCI_LOOKUP_COMPLETE标志位不会被置位
    */
    int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended);
    

5 代码实战

现在有一个配置文件,文件名:/etc/config/testconfig

配置文件内容:

config  "server" "webserver"
        list    "index" "index.html"
        list    "index" "index.php"
        list    "index" "default.html"
        option  "addr"  "/home/hess"
  1. 遍历 list

    int ForeachList()
    {
        struct uci_context *pUciContext = NULL;		//定义一个UCI上下文
        struct uci_package *pUciPackage = NULL;
        struct uci_element *pUciElement = NULL;
    
        pUciContext = uci_alloc_context();			//申请一个UCI上下文
        if (UCI_OK != uci_load(pUciContext, "testconfig", &pUciPackage))		//如果打开UCI文件失败,则清理UCI上下文
        {
            printf("[%s][%d] Error uci_load!\n", __FILE__, __LINE__);
        	UciFreeContext(&pUciContext);
        	return -1;
        }
    
        /* 遍历一个package,一个package有几个section就循环几次 */
        uci_foreach_element(&pUciPackage->sections, pUciElement)
        {
            /* 将一个element转换为section类型 */
            struct uci_section *pUciSection = uci_to_section(pUciElement);
    
            /* uci_lookup_option()获取当前节的一个值 */
            struct uci_option *pUciOption = uci_lookup_option(pUciContext, pUciSection, "index");
    
            /* Option的类型有UCI_TYPE_STRING和UCI_TYPE_LIST两种 */
            if ((NULL != pUciOption) && (UCI_TYPE_LIST == pUciOption->type))
            {
                struct uci_element *pUciListElement = NULL;
    
                uci_foreach_element(&pUciOption->v.list, pUciListElement)		//遍历list
                {
                    //依次打印 index.html index.php default.html
                    printf("[%s][%d] value: %s\n", __FILE__, __LINE__, pUciListElement->name);        
                }
                break;	//退出遍历package
            }
        }
    
        uci_unload(pUciContext, pUciPackage);		//释放pUciPackage
        UciFreeContext(&pUciContext);				//释放UCI上下文
    
        return 0;
    }
    
  2. 获取 option 的值

    int GetOptionValue()
    {
        struct uci_context *pUciContext = NULL;		//定义一个UCI上下文
        struct uci_package *pUciPackage = NULL;
        struct uci_element *pUciElement = NULL;
    
        pUciContext = uci_alloc_context();			//申请一个UCI上下文
        if (UCI_OK != uci_load(pUciContext, "testconfig", &pUciPackage))		//如果打开UCI文件失败,则清理UCI上下文
        {
            printf("[%s][%d] Error uci_load!\n", __FILE__, __LINE__);
        	UciFreeContext(&pUciContext);
        	return -1;
        }
    
        /* 遍历一个package,一个package有几个section就循环几次 */
        uci_foreach_element(&pUciPackage->sections, pUciElement)
        {
            /* 将一个element转换为section类型 */
            struct uci_section *pUciSection = uci_to_section(pUciElement);
            char *pValue = NULL;
    
            if (NULL != (pValue = uci_lookup_option_string(ctx, pUciSection, "addr")))        //pValue得到"/home/hess"
            {
    			//如果您想持有该变量值,一定要拷贝一份。当pkg销毁后value的内存会被释放。strdup()会动态申请内存,使用后需要手动释放内存
                ip = strdup(pValue);
            }
            
            free(pValue);
            break;        //退出遍历package
        }
    
        uci_unload(pUciContext, pUciPackage);		//释放pUciPackage
        UciFreeContext(&pUciContext);				//释放UCI上下文
    
        return 0;
    }
    
  3. 设置 option 的值

    方法一

    struct uci_context *_ctx = uci_alloc_context(); //申请上下文
    struct uci_ptr ptr ={
        .package = "testconfig",
        .section = "webserver",
        .option = "addr",
        .value = "/home/hess",
    };
    
    uci_set(_ctx, &ptr); 				//写入配置
    uci_commit(_ctx, &ptr.p, false); 	//提交保存更改
    uci_unload(_ctx, ptr.p); 			//卸载包
    
    uci_free_context(_ctx); 			//释放上下文
    

    方法二

    /* 传入的值依次是testconfig webserver addr /homo/hess,就可以将testconfig的addr选项设置成/home/hess */
    int SetUciElement(const char *pConfigName, const char *pSectionName, const char *pElementName, const char *pElementValue)
    {
        struct uci_context *pUciContext = NULL;
        struct uci_ptr uciPtr;
        int ret = UCI_OK;
        char uciOptionName[128] = {0};
    
        if (pConfigName == NULL || pSectionName == NULL || pElementName == NULL || pElementValue == NULL)
        {
            printf("[%s][%d] input params is null.\n", __FILE__, __LINE__);
            return -1;
        }
    
        ContructUciPtr(pConfigName, pSectionName, pElementName, uciOptionName);
    
        pUciContext = uci_alloc_context();
        if (pUciContext == NULL)
        {
    		printf("[%s][%d] pUciContext alloc error.\n", __FILE__, __LINE__);
    		return -1;
        }
    
        if (uci_lookup_ptr(pUciContext, &uciPtr, uciOptionName, true) != UCI_OK)
        {
    		printf("[%s][%d] uci_lookup_ptr error.\n", __FILE__, __LINE__);
    		uci_free_context(pUciContext);
        	return -1;
        }
    
        uciPtr.value = pElementValue;
        printf("[%s][%d] %s %s %s %s\n", __FILE__, __LINE__, uciPtr.package, uciPtr.section, uciPtr.option,  uciPtr.value);
    
        ret = uci_set(pUciContext, &uciPtr);
        if(ret != UCI_OK)
        {
    		printf("[%s][%d] uci_set error.\n", __FILE__, __LINE__);
    		uci_free_context(pUciContext);
    		return ret;
        }
    
        ret = uci_commit(pUciContext, &uciPtr.p, false);
        if(ret != UCI_OK)
        {
    		printf("[%s][%d] uci_commit error.\n", __FILE__, __LINE__);
    		uci_free_context(pUciContext);
    		return ret;
        }
    
        uci_free_context(pUciContext);
        return ret;
    }
    

网上的代码也可用,写的也不错,参考如下链接:https://blog.csdn.net/u012819339/article/details/96320736

6 文章参考

[1] http://www.openwrt.pro/post-37.html
[2] https://blog.csdn.net/u012819339/article/details/50752157
[3] https://blog.csdn.net/u012819339/article/details/96320736

  • 12
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
OpenWRT是一个基于Linux的嵌入式操作系统,它提供了一套名为UCI(Unified Configuration Interface)的配置接口,用于管理系统的配置文件。UCI提供了C语言接口,使开发者可以通过编程方式读取和修改系统配置。 在使用OpenWRTUCI C语言接口之前,需要包含相应的头文件和链接相关的文件。头文件是`uci.h`,文件是`libuci.so`。 下面是一个简单的例子,演示如何使用UCI C语言接口读取和修改配置: ```c #include <stdio.h> #include <uci.h> int main() { struct uci_context *ctx = uci_alloc_context(); if (!ctx) { fprintf(stderr, "Failed to allocate UCI context\n"); return 1; } struct uci_package *pkg; if (uci_load(ctx, "wireless", &pkg) != UCI_OK) { fprintf(stderr, "Failed to load wireless package\n"); uci_free_context(ctx); return 1; } struct uci_element *elem; uci_foreach_element(&pkg->sections, elem) { struct uci_section *section = uci_to_section(elem); const char *name = section->e.name; const char *option_value = uci_lookup_option_string(ctx, section, "option_name"); printf("Section: %s\n", name); printf("Option value: %s\n", option_value); } uci_unload(ctx, pkg); uci_free_context(ctx); return 0; } ``` 上述代码中,首先通过`uci_alloc_context()`函数分配一个UCI上下文对象。然后使用`uci_load()`函数加载指定的配置包(这里是"wireless")。接着使用`uci_foreach_element()`函数遍历配置包中的所有节(section),并通过`uci_lookup_option_string()`函数获取指定选项(option)的值。最后,使用`uci_unload()`函数卸载配置包,并通过`uci_free_context()`函数释放UCI上下文对象。 以上是一个简单的示例,你可以根据具体的需求进一步扩展和修改代码。希望对你有帮助!如有其他问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半砖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值