LUCI 的配置文件一般存储在 /etc/config 目录下。比如网络配置文件则是 /etc/config/network,无线的配置文件是 /etc/config/wireless。更多配置文件的含义参考官方 WIKI.
这里画一个图让大家大致了解配置文件的内容和 uci 的几个基本结构之间的对应关系。(例举文件为 uhttpd 的配置文件)
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;
};
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);
现在有一个配置文件,文件名:/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
[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