OpenWRT UCI API的使用经验

   参考https://blog.csdn.net/KOBE_ZERO/article/details/51496761, 测试了以下使用libuci 读写配置文件, 读程序没问题,但写入程序不成功。函数摘录如下:

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

uci_set, uci_commit ,uci_unload返回值都是失败, 分别是3,2,2, 折腾好久,找不到原因。    

    网上搜索到一篇关于libuci库中的结构体的文章: https://blog.csdn.net/KOBE_ZERO/article/details/51496761

注意到结构体,以下四个成员都是const, 说明uci_set函数第二个ptr参数肯定是做输入用

    const char *package;
    const char *section;
    const char *option;
    const char *value;

      
     后面三个参数好理解,package是个什么东东? 改成配置文件名:testconfig, 执行程序, 上面代码中8,9,10三行代码的函数返回值打印出来
返回值为2,0,0, 后面两个调用成功了, uci_set调用失败!

     继续郁闷, 网上搜索在搜索,每没有找到答案!
     
     用命令行工具试试吧!

      uci show                 //将显示所有配置文件中的所有配置项目
显示:
    uci testconfig.@servver[0]=servver
    uci testconfig.@servver[0].value='123'

执行:  uci set testconfig.servver.value=123
显示:
    uci: Invalid argument

        失败! 到底啥子原因呢?。。。。。。。 郁闷很久。。。。。

无意中,执行: uci set testconfig.servver=cfg-type
再执行了下自己的程序, 哇草, 三个函数的返回值都是0,忙打开文件看看内容:
config servver
    option value '123'

config cfg-type 'servver'
    option value '256'

配置文件变了, 注意到了文件增加了一个section。再回去看看:https://blog.csdn.net/u013485792/article/details/52538371

UCI文件语法举例:
config 'section-type' 'section'
        option  'key'       'value'
        list    'list_key'  'list_value'

原来前面那个config节点, servver表示section-type, 其“section”或者叫section-name更好一点不存在, 它是匿名的, 你用uci show查看
testconfig.@servver[0]=servver
testconfig.@servver[0].value='123'
testconfig.servver=cfg-type
testconfig.servver.value='256'

发现@符号没?

经过实验, 总结以下经验:

  1) libuci无论数读写配置文件, 配置文件都必须存在, libuci不负责磁盘文件建立
  2) libuci上下文会保存全部配置文件的配置信息, 当你程序中打开uci上下文后,你在控制台使用uci命令行输入的信息也包含在其中,两者是“通”的
   3)  当你需要修改/增加一个option时, option所在的section必须已经存在, 否则写入会失败

--------个人以为,既然使用了uci的配置规范,程序自己修改配置文件的话完全没必要
----- uci命令行工具已经帮我们做好了统一的配置修改命令,
--------代码中只需要读配置信息就可以了, 对缺少的配置, 程序给出提示信息供程序使用人员参考,提示使用者执行相应的uci set 命令加以配置就可以了


       下面给一个遍历所由配置项目的函数, 在https://blog.csdn.net/KOBE_ZERO/article/details/51496761提供代码上改的:

#define UCI_CONFIG_FILE "testconfig"         //不带路径, 目录为默认目录/etc/config/

int dump_config()
{
     char* value;
    struct uci_element *e, *e1;
    struct uci_package * pkg = NULL;
    struct uci_context * ctx = NULL;

    do{
        ctx = uci_alloc_context(); // 申请一个UCI上下文.
        if(!ctx) break;
        if(UCI_OK != uci_load(ctx, UCI_CONFIG_FILE, &pkg)) break;

        /*遍历UCI的每一个节*/
        uci_foreach_element(&pkg->sections, e){
            struct uci_section *s = uci_to_section(e);
            printf("config\t %s\t %s\t \n", s->type, e->name);
            // 将一个 element 转换为 section类型, 如果节点有名字,则 s->anonymous 为 false.
            // 此时通过 s->e->name 来获取.
            // 此时 您可以通过 uci_lookup_option()来获取 当前节下的一个值.
            if (NULL != (value = uci_lookup_option_string(ctx, s, "ipaddr")))
              {
            //    printf("uci_element.name=%s,  ipaddr = %s\n", e->name, value);
              // char* ip = strdup(value); //如果您想持有该变量值,一定要拷贝一份。当 pkg销毁后value的内存会被释放。
              }

              {

                uci_foreach_element(&s->options, e1){
                    struct uci_option *opt = uci_to_option(e1);
                    if(UCI_TYPE_STRING == opt->type)
                        printf("\t option %s  %s\t \n", opt->e.name, opt->v.string);
                    else if(UCI_TYPE_LIST == opt->type){
                        uci_foreach_element(&opt->v.list, e2){
                            printf("\t list %s  %s\t \n", opt->e.name, e2->name);
                        }
                }
             }
        }


        uci_unload(ctx, pkg); // 释放 pkg
        uci_free_context(ctx);
        return 0;
    }while(0);
cleanup:
    if(pkg) uci_unload(ctx, pkg); // 释放 pkg
    if(ctx) uci_free_context(ctx);
    ctx = NULL;
    return -1;
}

一点补充说明:

        uci配置有两种:option和list,  配置文件中出现key重复的option, 则以最后一个option为准;配置文件中出现key重复的list, 则全部keyvalue组成一个数组提供个应用程序使用。 配置的例子:

config rule
    option name 'alice'
    option name 'bob'         -----以后一个为准
 
    list icmp_type 'echo-request'
    list icmp_type 'echo-reply'
    list icmp_type 'destination-unreachable'
    list icmp_type 'packet-too-big'
    list icmp_type 'time-exceeded'
    list icmp_type 'bad-header'
    list icmp_type 'unknown-header-type'

猜你喜欢

转载自blog.csdn.net/twd_1991/article/details/80401098