)
嵌入式操作系统 | uci 配置读写命令行 libuci本课程开源地址Giteehttps://gitee.com/fujianxinxi/qianrushixitongyingyongkaifa.git课件、示例代码与验收脚本都在该仓库可直接git clone或下载 ZIP 使用。模块六 · 2 学时 · 环境VMware Ubuntu 20.04一句话概述直接用 /etc/configlibuci 的默认目录和 OpenWrt 一样来学 uci先建一个串口配置文件再一条命令一步地 set、show、commit、get、delete 看结果最后用 libuci 在 C 程序里读了 5 个串口参数、改掉波特率并写回文件配套课堂练习与课后作业。本节目标能看懂 uci 配置文件config / option 结构说出它和普通 ini 的区别会用uci set / show / commit / get / delete一条条操作/etc/config里的配置并看懂结果会在 C 程序里用 libuci 读配置、改配置并提交保存知道什么时候要 sudo一、讲解内容1.1 知识讲解uci 是什么。OpenWrt 把系统配置统一成了 uci 格式一个配置文件里可以有多个节section每个节里是若干个选项option。路由器上的网络、无线、防火墙配置全是它——嵌入式设备改配置通常就是改 uci。配置目录就是/etc/config本课最省事的地方。这个路径是 libuci编译时定死的默认值头文件里就写着#define UCI_CONFDIR /etc/config和 OpenWrt 完全一样。所以命令行不用加-cuci show serial就是看/etc/config/serialC 代码里不用设置目录uci_alloc_context()之后直接查比上一版少三行Ubuntu 上这个目录默认不存在所以第一次要sudo mkdir -p /etc/config建一次就行本课用串口配置当例子也正好和课时 22 / 23 的串口课呼应config serial main option device /dev/ttyV0 option baudrate 9600 option databits 8 option stopbits 1 option interval 5config serial main一个类型是 serial、名字是 main的节option baudrate 9600节里的一个选项值一律是字符串三条必须记住的规矩规矩说明文件必须先存在/etc/config里连文件都没有时uci set会报uci: Entry not found所以先touch一个空文件set 之后要 commitset只改内存里的副本commit才写进文件没 commit 时cat文件还是空的写/etc/config要 rootset/commit加sudo读不用uci show、uci get普通用户也能跑命令行和 C 库分工。命令行适合看和临时改程序里要自动读配置比如启动时读串口参数就用 libuciuci_alloc_context()→uci_lookup_ptr()取值 →uci_set()改值 →uci_commit()写回。1.2 操作步骤一条命令一步看结果第 1 步建配置目录Ubuntu 默认没有建一次就好sudomkdir-p/etc/configls-ld/etc/config现象drwxr-xr-x 2 root root 4096 Sep 25 08:32 /etc/config第 2 步建一个空的配置文件不建下一步就报错sudotouch/etc/config/serialls-l/etc/config/serial现象出现一个 0 字节的serial文件。可以故意跳过这步试试记住uci: Entry not found这个报错。第 3 步一条条设置注意这时还没写进文件sudoucisetserial.mainserial# 建一个类型 serial、名叫 main 的节sudoucisetserial.main.device/dev/ttyV0sudoucisetserial.main.baudrate9600sudoucisetserial.main.databits8sudoucisetserial.main.stopbits1sudoucisetserial.main.interval5uci show serial# 读不用 sudo现象show把已设置的内容打出来serial.mainserial serial.main.device/dev/ttyV0 serial.main.baudrate9600 serial.main.databits8 serial.main.stopbits1 serial.main.interval5第 4 步commit 才真正写进文件sudouci commit serialcat/etc/config/serial现象文件里出现标准 uci 格式config serial main option device /dev/ttyV0 option baudrate 9600 option databits 8 option stopbits 1 option interval 5没 commit 之前cat这个文件是空的——可以来回试几次把内存里的改动和文件里的内容分清楚。第 5 步读单项、改单项、删一项uci get serial.main.baudrate# 读一项 → 9600sudoucisetserial.main.baudrate115200sudouci commit serial uci get serial.main.baudrate# 再读 → 115200sudouci delete serial.main.stopbits# 删掉 stopbitssudouci commit serial uci show serial# stopbits 不见了sudoucisetserial.main.stopbits1# 为了下节课用加回来sudouci commit serial现象get每次只输出一个值delete之后show里看不到那一项。第 6 步编译并运行 C 程序libuci 读改配置cd~/lab/课时19-uci配置读写 gcc-Wall-Wextra-ouci_demo uci_demo.c-lucisudo./uci_demo现象C 程序读到 5 个串口参数把 baudrate 从 9600 改成 115200 并提交① 配置目录/etc/configlibuci 的默认值和 OpenWrt 一样命令行不用加 -c ② 读取串口配置 serial.main serial.main.device /dev/ttyV0 serial.main.baudrate 9600 serial.main.databits 8 serial.main.stopbits 1 serial.main.interval 5 ③ 把 baudrate 改成 115200 并提交写回 /etc/config/serial 修改成功 ④ 重新读一遍应为 115200说明真的写进文件了 serial.main.baudrate 115200 ⑤ 完成第 7 步不加 sudo 会怎样现象很重要./uci_demo现象读的部分照样能打印出来读不需要权限但改的时候失败③ 把 baudrate 改成 115200 并提交写回 /etc/config/serial commit: Permission denied 修改失败写 /etc/config 需要 root用 sudo ./uci_demo 再试一次第 8 步用命令行核对 C 程序真的写进去了uci get serial.main.baudrate# → 115200cat/etc/config/serial# 文件里 baudrate 也是 115200第 9 步选做和课时 23 联动课时 23 写的串口程序serial_uloop.c里把device、baudrate这些参数改成从这份配置里读——硬编码换成配置文件程序就更像产品了课上只演示改device一处就够。1.3 常见错误与排查现象原因解决uci: Entry not found/etc/config里还没有这个配置文件sudo touch /etc/config/serialuci show serial什么都没有改完没commit改动只在内存sudo uci commit serialcommit: Permission denied没用 sudo 写 root 的文件加sudo读操作不用C 程序打印(没有这一项)配置文件名/节名/选项名写错用uci show serial对照键名格式文件.节.选项uci_perror: lookup: Entry not found同上键名对不上同上gcc: cannot find -luci课时 15 的 uci 没装好回课时 15 执行ls -l /usr/local/lib/libuci.so缺了按第 5 步重装libuci.so: cannot open shared object file装完库没sudo ldconfig回课时 15 执行sudo ldconfig二、学生练习本节命令速查表命令作用示例sudo mkdir -p /etc/config建配置目录首次—sudo touch /etc/config/串口文件建空配置文件sudo touch /etc/config/serialsudo uci set 键值设置一项改内存sudo uci set serial.main.baudrate9600uci get 键 / uci show 节读一项 / 看全部不用 sudouci show serialsudo uci commit 文件把改动写进文件sudo uci commit serialsudo uci delete 键删一项sudo uci delete serial.main.stopbitsgcc … -luci编译 libuci 程序gcc -Wall -Wextra -o uci_demo uci_demo.c -lucisudo ./uci_demo运行写文件要 rootsudo ./uci_demo编号任务提示预期结果L19.1按步骤建立串口配置并 show第 2~4 步uci show serial六行文件里有config serial mainL19.2不 touch 直接 set换一个新文件试如/etc/config/test看到uci: Entry not foundL19.3set 之后不 commit 就 cat看文件内容文件还是空的L19.4改 baudrate 再 get第 5 步get 输出你改的值L19.5delete 一项再 show第 5 步show里该项消失L19.6运行 C 程序读改配置先sudo ./uci_demo再./uci_demo前者修改成功后者报 Permission deniedL19.7加一个新配置文件sudo touch /etc/config/gateway并设几项uci show gateway能看到三、作业必做完成 L19.1、L19.3、L19.6提交截图uci show serial/cat /etc/config/serial/ C 程序输出与Permission denied现象并回答① uci 的config和option各是什么② 为什么 set 之后必须 commit③ 为什么读配置不用 sudo写配置要 sudo选做在 C 程序里再加一个option parity none的读取和打印把课时 23 的串口程序serial_uloop.c改成从/etc/config/serial读device和baudrate提交截图 文字回答命名课时19-作业截图.png四、本节小结与下节预告本节一条命令一步地摸熟了 uci/etc/config的默认目录、配置文件的形状、set/show/get/commit/delete 的用法以及 C 程序里用 libuci 读改配置顺便搞清了什么时候要 sudo。下节课把程序的状态暴露出去写一个 ubus 对象让别的程序用ubus call一查就知道我们在干什么。附录怎么运行 完整代码一个课件就够用先按附录 A 一条命令一步地敲写 /etc/config 要 sudo读不用再按附录 B 抄代码。行尾请用 LF。附录 A怎么运行注意先后顺序# 首次建配置目录和空的配置文件Ubuntu 默认没有 /etc/configsudomkdir-p/etc/configsudotouch/etc/config/serial# 一条条设置写操作要 sudo读不用sudoucisetserial.mainserialsudoucisetserial.main.device/dev/ttyV0sudoucisetserial.main.baudrate9600sudoucisetserial.main.databits8sudoucisetserial.main.stopbits1sudoucisetserial.main.interval5uci show serial# 看内存里的改动sudouci commit serial# 写进 /etc/config/serialcat/etc/config/serial# 看文件# 编译并运行 C 程序读 5 个参数、把 baudrate 改成 115200gcc-Wall-Wextra-ouci_demo uci_demo.c-lucisudo./uci_demo# 写文件要 root./uci_demo# 不加 sudo读得到、改不了Permission denieduci get serial.main.baudrate# 命令行核对附录 B文件uci_demo.c/* * uci_demo.c —— 课时 19用 libuci 读、改配置文件 * * 编译gcc -Wall -Wextra -o uci_demo uci_demo.c -luci * 运行sudo ./uci_demo # 要写 /etc/config 就需要 root只想看的话 ./uci_demo 也行 * * 本课配置目录就是 /etc/config —— 这是 libuci 编译时定死的默认值和 OpenWrt 一样 * 所以代码里不用再设置目录命令行也不用加 -c最省事。 * * 三件事① 读出串口配置 ② 把 baudrate 改成 115200 并提交 ③ 重新读一遍验证 */#includestdio.h#includestring.h#includeuci.hstaticstructuci_context*ctx;/* 读一个配置项并打印找不到就打印没有这一项 */staticvoidshow(constchar*key){structuci_ptrptr{0};charbuf[128];snprintf(buf,sizeof(buf),%s,key);/* uci_lookup_ptr 会改字符串所以给副本 */if(uci_lookup_ptr(ctx,ptr,buf,true)!UCI_OK||!ptr.o){printf( %-24s (没有这一项)\n,key);return;}printf( %-24s %s\n,key,ptr.o-v.string?ptr.o-v.string:(空));}/* 把某个配置项设成指定值并提交写回文件 */staticintset_and_commit(constchar*key,constchar*value){structuci_ptrptr{0};structuci_package*pkgNULL;charbuf[128];snprintf(buf,sizeof(buf),%s,key);if(uci_lookup_ptr(ctx,ptr,buf,true)!UCI_OK){uci_perror(ctx,lookup);return-1;}ptr.valuevalue;if(uci_set(ctx,ptr)!UCI_OK){uci_perror(ctx,set);return-1;}pkgptr.p;if(uci_commit(ctx,pkg,false)!UCI_OK){/* 写文件需要 root 权限 */uci_perror(ctx,commit);return-1;}return0;}intmain(void){ctxuci_alloc_context();if(!ctx){printf(申请 uci 上下文失败\n);return1;}printf(① 配置目录/etc/configlibuci 的默认值和 OpenWrt 一样命令行不用加 -c\n\n);printf(② 读取串口配置 serial.main\n);show(serial.main.device);show(serial.main.baudrate);show(serial.main.databits);show(serial.main.stopbits);show(serial.main.interval);printf(\n③ 把 baudrate 改成 115200 并提交写回 /etc/config/serial\n);if(set_and_commit(serial.main.baudrate,115200)!0){printf( 修改失败写 /etc/config 需要 root用 sudo ./uci_demo 再试一次\n);}else{printf( 修改成功\n);}printf(\n④ 重新读一遍应为 115200说明真的写进文件了\n);show(serial.main.baudrate);uci_free_context(ctx);printf(\n⑤ 完成\n);return0;}