1 LUCI 配置文件简介
LUCI 的配置文件一般存储在 /etc/config 目录下。比如网络配置文件则是 /etc/config/network,无线的配置文件是 /etc/config/wireless。更多配置文件的含义参考官方 WIKI.
2 简单的基本关系
这里画一个图让大家大致了解配置文件的内容和 uci 的几个基本结构之间的对应关系。(例举文件为 uhttpd 的配置文件)
3 结构体介绍
-
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; };
-
struct uci_section:节结构体,它对应配置文件中的节。
struct uci_section { struct uci_element e; struct uci_list options; struct uci_package *package; bool anonymous; char *type; };
-
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; };
-
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; };
-
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介绍
-
uci_alloc_context:动态申请一个 uci 上下文结构。
struct uci_context *uci_alloc_context(void);
-
uci_free_contex:释放由 uci_alloc_context 申请的 uci 上下文结构且包括它的所有数据。
void uci_free_context(struct uci_context *ctx);
-
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"
-
遍历 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; }
-
获取 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; }
-
设置 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