一、我来说LuCI: LuCI官方----2.UCI

中文总结:

1. UCI是基于NVRAM的系统配置工具;
2. UCI的语法格式, /etc/config;


package 'example'


config 'example' 'test'
        option   'string'      'some value'
        option   'boolean'     '1'
        list     'collection'  'first item'
        list     'collection'  'second item'



3. uci命令行,系统配置;




http://wiki.openwrt.org/doc/uci, 英文原版:


The UCI System

The abbreviation UCI stands for Unified Configuration Interface and is intended to centralize the configuration of OpenWrt.

Configuration should be easy and straightforward, making life easier! UCI is all about that. It is the successor to the NVRAM-based configuration found in the White Russian series of OpenWrt. UCI can be seen as OpenWrt's main configuration user interface for the most important system settings. Typically, these are settings that are crucial for the functioning of the device, such as are typically found in the web interface of routers and embedded devices; that is, functionality that is integrated in the system builds. Examples are the main network interface configuration, wireless settings, logging functionality and remote access configuration.

In addition, selected third party programs have been made compatible with the UCI system, so these can be managed more easily as well. Many programs have their own configuration files lying around somewhere, like/etc/network/interfaces/etc/exports/etc/dnsmasq.conf or /etc/samba/smb.conf and they often use different syntaxes. With OpenWrt, you don't have to bother with any of them and need to change only the UCI configuration file(s). Of course, most of the software that you would like to install will not have been prepared for UCI configuration, which is a good thing, because oftentimes you will want the full power of an application's own configuration interface, as it was intended by the developers. Therefore, only a few selected programs which benefit from availability of a centralised configuration have been made UCI-compatible by the OpenWrt package maintainers (see the UCI configuration file list below).

Most applications (save some that are made in-house) are made UCI-compatible by the package maintainer by simply writing the original configuration file (which is read by the program) according to the chosen settings in the corresponding UCI file. This is done upon running the initialization scripts in /etc/init.d/. See Init scripts for more information. Thus, when starting a daemon with such an UCI-compatible initialization script, you should be aware that the program's original configuration file gets overwritten. For example, in the case of Samba/CIFS, the file /etc/samba/smb.conf is overwritten with UCI settings from the UCI configuration file /etc/config/samba when running/etc/init.d/samba start. In addition, the application's configuration file is often stored in RAM instead of in flash, because it does not need to be stored in non-volatile memory and it is rewritten after every change, based on the UCI file. There are ways to disable UCI in case you want to adjust settings in the original configuration file not available through UCI. FIXME add the recommended way please, or link to it.

For those non-UCI compatible programs, there is a convenient list of some non-UCI configuration files you may want to tend to. Note that, for most third party programs, you should consult the program's own documentation.

Common Principles

OpenWrt's central configuration is split into several files located in the /etc/config/ directory. Each file relates roughly to the part of the system it configures. You can edit the configuration files with a text editor or modify them with the command line utility program uci. UCI configuration files are also modifiable through various programming APIs (like Shell, Lua and C), which is also how web interfaces like LuCI make changes to the UCI files.

Upon changing a UCI configuration file, whether through a text editor or the command line, the services or executables that are affected must be (re)started by an init.d call, such that the updated UCI configuration is applied to them. Many programs are made compatible with UCI in this way by making their init.d script write their standard software specific configuration files. The init.d script first properly writes such a configuration file to the software's expected location and it is read in again by restarting the executable. Note that just (re)starting the executable directly, without init.d calls, will not result in an UCI update to relegate UCI config to the program's expectedconfiguration file. Changes in files in /etc/config/ then take no effect.

As an example of modifying the UCI configuration, suppose you want to change the device's IP address from the default 192.168.1.1 to 192.168.2.1. To do this, using any text editor, such as vi, change the line

option ipaddr 192.168.1.1

in the file /etc/config/network to:

option ipaddr 192.168.2.1

Next, commit the settings by running

/etc/init.d/network restart

In this case, remember that you have to login again using SSH as the device is now accessible at its new IP address!

Configuration Files

File Description
Basic
/etc/config/dhcp Dnsmasq configuration and DHCP settings
/etc/config/dropbear SSH server options
/etc/config/firewall NAT, packet filter, port forwarding, etc.
/etc/config/network Switch, interface and route configuration
/etc/config/system Misc. system settings
/etc/config/timeserver Time server list for rdate
/etc/config/wireless Wireless settings and wifi network definition
IPv6
/etc/config/6relayd IPv6-Server and Relay (RD, DHCPv6 & NDP)
/etc/config/ahcpd Ad-Hoc Configuration Protocol (AHCP) server and forwarder configuration
/etc/config/aiccu AICCU client configuration
/etc/config/dhcp6c WIDE-DHCPv6 client
/etc/config/dhcp6s WIDE-DHCPv6 server
/etc/config/gw6c GW6c client configuration
/etc/config/radvd Router Advertisement (radvd) configuration
Other
/etc/config/bbstored BoxBackup server configuration
/etc/config/ddns Dynamic DNS configuration (ddns-scripts)
/etc/config/etherwake Wake-on-Lan: etherwake
/etc/config/freifunk_p2pblock Uses iptables layer7-, ipp2p- and recent-modules to block p2p/filesharing traffic
/etc/config/fstab Mount points and swap
/etc/config/hd-idle Another idle-daemon for attached hard drives
/etc/config/httpd Web server options (Busybox httpd, deprecated)
/etc/config/ipset-dns Configure http://git.zx2c4.com/ipset-dns/about/ ipset-dns
/etc/config/luci Base LuCI config
/etc/config/luci_statistics Configuration of Statistics packet
/etc/config/mini_snmpd mini_snmpd settings
/etc/config/minidlna MiniDLNA settings
/etc/config/mjpg-streamer Streaming application for Linux-UVC compatible webcams
/etc/config/mountd OpenWrt automount daemon
/etc/config/mroute Configuration files for multiple WAN routes
/etc/config/multiwan Simple multi WAN configuration
/etc/config/ntpclient Getting the correct time
/etc/config/p910nd config for non-spooling Printer daemon p910nd.server
/etc/config/pure-ftpd Pure-FTPd server config
/etc/config/qos Implementing Quality of Service for the upload
/etc/config/racoon racoon IPsec daemon
/etc/config/samba settings for the Microsoft file and print services daemon
/etc/config/snmpd SNMPd settings
/etc/config/sshtunnel Settings for the package sshtunnel
/etc/config/stund STUN server configuration
/etc/config/tinc tinc package configuration
/etc/config/transmission BitTorrent configuration
/etc/config/uhttpd Web server options (uHTTPd)
/etc/config/upnpd miniupnpd UPnP server settings
/etc/config/users user database for different services
/etc/config/ushare uShare UPnP server settings
/etc/config/vblade vblade userspace AOE target
/etc/config/vnstat vnstat downloader settings
/etc/config/wifitoggle Script to toogle WiFi with a button
/etc/config/wol Wake-on-Lan: wol
/etc/config/wshaper wondershaper qos script settings
/etc/config/znc ZNC bouncer configuration

File Syntax

The UCI configuration files usually consist of one or more config statements, so called sections with one or more option statements defining the actual values.

Below is an example of a simple configuration file:

package 'example'

config 'example' 'test'
        option   'string'      'some value'
        option   'boolean'     '1'
        list     'collection'  'first item'
        list     'collection'  'second item'

  • The  config 'example' 'test' statement defines the start of a section with the type  example and the name  test. There can also be so called anonymous sections with only a type, but no name identifier. The type is important for the processing programs to decide how to treat the enclosed options.
  • The  option 'string' 'some value' and  option 'boolean' '1' lines define simple values within the section. Note that there are no syntactical differences between text and boolean options. Per convention, boolean options may have one of the values '0', 'no', 'off' or 'false' to specify a false value or '1' , 'yes', 'on' or 'true' to specify a true value.
  • In the lines starting with a  list keyword an option with multiple values is defined. All  list statements that share the same name,  collection in our example, will be combined into a single list of values with the same order as in the configuration file.
  • The indentation of the  option and  list statements is a convention to improve the readability of the configuration file but it's not syntactically required.
  • If an option is absent and not required, the default value is assumed. If it is absent and required, it may trigger an error in the application or other unwanted behaviour.

Usually you do not need to enclose identifiers or values in quotes. Quotes are only required if the enclosed value contains spaces or tabs. Also it's legal to use double- instead of single-quotes when typing configuration options.

All of the examples below are valid UCI syntax:

  • option example value
  • option 'example' value
  • option example "value"
  • option "example" 'value'
  • option 'example' "value"

In contrast, the following examples are not valid UCI syntax:

  • option 'example" "value' (quotes are unbalanced)
  • option example some value with space (note the missing quotes around the value)

It is important to know that UCI identifiers and config file names may contain only the characters a-z0-9 and _. E.g. no hyphens (-) are allowed. Option values may contain any character (as long they are properly quoted).

Command Line Utility

For adjusting settings, one normally changes the UCI config files directly. However, for scripting purposes, all of UCI configuration can also be read and changed using the ucicommand line utility. For developers requiring automatic parsing of the UCI configuration, it is therefore redundant, unwise, and inefficient to use awk and grep to parse OpenWrt's config files. The uci utility offers all functionality with respect to modifying and parsing UCI.

Below is the usage, as well as some useful examples of how to use this powerful utility.

 When using uci to write configuration files, the files are always rewritten in whole and non-recognised commands are omitted. This means that any extraneous lines in the file are deleted, such as comments. If you have UCI configuration files that you have edited yourself and you want to preserve your own comments and blank lines, you should not use the command line utility but edit the files normally. Note that some files, such as the uHTTPd configuration file, already contain many comments when the application is first installed. Also, note that some applications such as LuCI also use the uci utility and thus may rewrite UCI configuration files.

When there are multiple rules next to each other, UCI uses array-like references for them. If there are 8 NTP servers, UCI will let you reference their sections astimeserver.@timeserver[0] for the first or timeserver.@timeserver[7] for the last one. You can also use negative indexes, such as timeserver.@timeserver[-1]. "-1" means the last one, "-2" means the second-to-last one, and so on. This comes in very handy when appending new rules to the end of a list. See the examples below.

Usage

root@OpenWrt:/lib/config#uci

Usage: uci [<options>] <command> [<arguments>]

Commands:
	batch
	export     [<config>]
	import     [<config>]
	changes    [<config>]
	commit     [<config>]
	add        <config> <section-type>
	add_list   <config>.<section>.<option>=<string>
	show       [<config>[.<section>[.<option>]]]
	get        <config>.<section>[.<option>]
	set        <config>.<section>[.<option>]=<value>
	delete     <config>[.<section[.<option>]]
	rename     <config>.<section>[.<option>]=<name>
	revert     <config>[.<section>[.<option>]]

Options:
	-c <path>  set the search path for config files (default: /etc/config)
	-d <str>   set the delimiter for list values in uci show
	-f <file>  use <file> as input instead of stdin
	-m         when importing, merge data into an existing package
	-n         name unnamed sections on export (default)
	-N         don't name unnamed sections
	-p <path>  add a search path for config change files
	-P <path>  add a search path for config change files and use as default
	-q         quiet mode (don't print error messages)
	-s         force strict mode (stop on parser errors, default)
	-S         disable strict mode
	-X         do not use extended syntax on 'show'

Command Target Description
commit [<config>] Writes changes of the given configuration file, or if none is given, all configuration files, to the filesystem. All "uci set", "uci add", "uci rename" and "uci delete" commands are staged into a temporary location and written to flash at once with "uci commit". This is not needed after editing configuration files with a text editor, but for scripts, GUIs and other programs working directly with UCI files.
batch - Executes a multi-line UCI script which is typically wrapped into a here document syntax.
export [<config>] Exports the configuration in a machine readable format. It is used internally to evaluate configuration files as shell scripts.
import [<config>] Imports configuration files in UCI syntax.
changes [<config>] List staged changes to the given configuration file or if none given, all configuration files.
add <config> <section-type> Add an anonymous section of type section-type to the given configuration.
add_list <config>.<section>.<option>=<string> Add the given string to an existing list option.
show [<config>[.<section>[.<option>]]] Show the given option, section or configuration in compressed notation.
get <config>.<section>[.<option>] Get the value of the given option or the type of the given section.
set <config>.<section>[.<option>]=<value> Set the value of the given option, or add a new section with the type set to the given value.
delete <config>[.<section[.<option>]] Delete the given section or option.
rename <config>.<section>[.<option>]=<name> Rename the given option or section to the given name.
revert <config>[.<section>[.<option>]] Revert the given option, section or configuration file.

Examples:

Setting a value

If we want to change the listening port of the uHTTPd Web Server from 80 to 8080 we change the configuration in /etc/config/uhttpd :

root@OpenWrt:~#uci set uhttpd.main.listen_http=8080root@OpenWrt:~#uci commit uhttpdroot@OpenWrt:~#/etc/init.d/uhttpd restartroot@OpenWrt:~#

Done, now the configuration file is updated and uHTTPd listens on port 8080.

Export an entire configuration
root@OpenWrt:~#uci export httpdpackage 'httpd'config 'httpd'option 'port' '80'option 'home' '/www'root@OpenWrt:~#
Show the configuration "tree" for a given config
root@OpenWrt:~#uci show httpdhttpd.@httpd[0]=httpdhttpd.@httpd[0].port=80httpd.@httpd[0].home=/wwwroot@OpenWrt:~#
Display just the value of an option
root@OpenWrt:~#uci get httpd.@httpd[0].port80root@OpenWrt:~#
append an entry to a list
uci add_list system.ntp.server='0.de.pool.ntp.org'
replace a list completely
uci delete system.ntp.serveruci add_list system.ntp.server='0.de.pool.ntp.org'uci add_list system.ntp.server='1.de.pool.ntp.org'uci add_list system.ntp.server='2.de.pool.ntp.org'
Create a new named section of a given type

"uci add blah" will create a new _anonymous_ section of type blah. ie,

#touch /etc/config/playapp#uci show playapp#uci add playapp blahcfg02a4fc#uci show playappplayapp.@blah[0]=blah# uci commit && cat /etc/config/playapp config blah#

If you actually want a named section of that type, for instance,

config blah this_name option xxx yyyconfig blah other_name option xxx zzz

Then "uci add" cannot be used, instead, use this synt

#rm /etc/config/playapp && touch /etc/config/playapp# uci set playapp.myname=mysectiontype# uci set playapp.othername=mysectiontype# uci commit && uci show playappplayapp.myname=mysectiontypeplayapp.othername=mysectiontype# cat /etc/config/playapp config mysectiontype 'myname'config mysectiontype 'othername'
UCI paths

Consider this example config file:

# /etc/config/fooconfig bar 'first'option name 'Mr. First'config baroption name 'Mr. Second'config bar 'third'option name 'Mr. Third'

Then the paths below are equal in every group:

# Mr. Firstuci get foo.@bar[0].nameuci get foo.@bar[-0].nameuci get foo.@bar[-3].nameuci get foo.first.name# Mr. Seconduci get foo.@bar[1].nameuci get foo.@bar[-2].name# uci get foo.second.name won't work; label 'second' undefined.# Mr. Thirduci get foo.@bar[2].nameuci get foo.@bar[-1].nameuci get foo.third.name

If you show it, you get :

#uci show foofoo.first=barfoo.first.name=Mr. Firstfoo.@bar[0]=barfoo.@bar[0].name=Mr. Secondfoo.third=barfoo.third.name=Mr. Third

But if you used "uci show foo.@bar[0]", you will see:

#uci show foo.@bar[0]foo.first=barfoo.first.name=Mr. First:-(
Query interface state
root@OpenWrt:~#uci -P/var/state show network.wannetwork.wan=interfacenetwork.wan.ifname=eth0.1network.wan.proto=dhcpnetwork.wan.defaultroute=0network.wan.peerdns=0network.wan.device=eth0.1network.wan.ipaddr=10.11.12.13network.wan.broadcast=255.255.255.255network.wan.netmask=255.255.255.0network.wan.gateway=10.11.12.1network.wan.dnsdomain=network.wan.dns=10.11.12.100 10.11.12.200network.wan.up=1network.wan.lease_gateway=10.11.12.1network.wan.lease_server=10.11.12.25network.wan.lease_acquired=1262482940network.wan.lease_lifetime=5400network.wan.lease_hostname=x-10-11-12-13root@OpenWrt:~#
Add a firewall rule

This is a good example of both adding a firewall rule to forward the TCP SSH port, and of the negative (-1) syntax used with uci.

root@OpenWrt:~# uci add firewall ruleroot@OpenWrt:~# uci set firewall.@rule[-1].src=wanroot@OpenWrt:~# uci set firewall.@rule[-1].target=ACCEPTroot@OpenWrt:~# uci set firewall.@rule[-1].proto=tcproot@OpenWrt:~# uci set firewall.@rule[-1].dest_port=22root@OpenWrt:~# uci commit firewallroot@OpenWrt:~# /etc/init.d/firewall restart
Get WAN IP address
  • Backfire
    uci -P/var/state get network.wan.ipaddr
  • The uci state vars are deprecated and not used anymore for network related information. In Trunk (not really uci) do
    . /lib/functions/network.sh; network_get_ipaddr ip wan; echo $ip
Get WAN interface
  • Backfire
    uci -P/var/state get network.wan.ifname
  • The uci state vars are deprecated and not used anymore for network related information. In Trunk (not really uci) do
    . /lib/functions/network.sh; network_get_device if_wan wan; echo $if_wan
  • Or
    . /lib/functions/network.sh; network_get_physdev if_wan wan; echo $if_wan
Get SSID

 uci get wireless.@wifi-iface[-1].ssid

Defaults:

To set some system defaults the first time the device boots, create a script in the folder

/etc/uci-defaults/
All scripts in that folder are automatically executed by  /etc/init.d/boot and if they exited with code 0  deleted afterwards (scripts that did not exit with code 0 are not deleted and will be re-executed during the next boot until they also successfully exit).

Porting UCI to a different Linux distribution




<think>我们遇到的问题是:在Lua脚本中尝试加载`luci.model.uci`模块时,出现了循环依赖或模块加载错误。 具体错误信息:`lua: ./uci.lua:27: loop or previous error loading module 'uci'` 首先,这个错误通常表示在加载模块时出现了循环依赖(即两个模块互相依赖)或者之前加载该模块时已经出错。 观察代码,我们的模块名为`luci.model.test`,并且在其中我们尝试加载`luci.model.uci`模块。注意,`uci`模块的路径是`luci.model.uci`,而我们的模块是`luci.model.test`,它们位于同个父模块`luci.model`下。 在Lua中,`require`函数加载模块时会避免重复加载相同的模块。但是,如果模块之间存在循环依赖,或者某个模块在加载过程中出错,则可能导致后续加载失败。 错误信息指向了`uci.lua`文件的第27行,这可能是由于在`uci.lua`文件中尝试加载了当前模块(即`luci.model.test`)?或者`uci`模块本身在加载时出现了其他错误? 但是,我们并没有看到`uci.lua`的代码,所以只能根据经验推测。 另外,注意我们代码中的模块定义方式: module("luci.model.test", package.seeall) 这种定义方式在Lua5.1中是常见的,但在更高版本中可能被弃用。而且,这种方式可能会改变当前模块的环境,从而导致些问题。 在OpenWrt的LuCI中,通常使用这种模块定义方式,但是需要注意避免循环依赖。 可能的原因: 1. 循环依赖:`luci.model.uci`模块在加载时,又尝试加载了`luci.model.test`模块(或者间接依赖了它),从而形成循环。 2. 模块加载顺序:在加载`luci.model.uci`之前,可能已经加载过但失败了,导致后续加载直接报错。 然而,我们注意到错误信息中提到了`./uci.lua:27`,这个文件可能是`uci`模块的文件。因此,我们需要检查该文件中第27行附近的代码,看看是否有错误。 由于我们无法直接查看`uci.lua`,我们可以尝试以下步骤来解决: 步骤1:检查`uci`模块的加载是否独立成功。 我们可以单独测试加载`uci`模块: lua -e 'print(require("luci.model.uci"))' 如果这个命令也报错,说明`uci`模块本身有问题,或者它的依赖有问题。 步骤2:如果`uci`模块可以单独加载,那么问题可能在于我们的模块加载方式。 在Lua中,使用`module`函数定义模块会创建个新的环境,并且可能会覆盖`require`等全局函数。因此,在模块内部使用`require`时,如果全局环境被改变,可能会导致问题。 我们可以尝试改变模块定义方式,使用更现代的方式,或者避免使用`module`函数。 例如,我们可以这样写: ```lua local M = {} local uci = require "luci.model.uci" function M.test() return 1 end return M ``` 然后,在加载时,使用`require("luci.model.test")`来加载这个模块。 步骤3:如果问题仍然存在,我们需要检查`luci.model.uci`模块是否依赖于当前模块(`luci.model.test`)。如果是,则形成了循环依赖,需要重新设计模块结构。 根据以上分析,我们尝试修改`luci.model.test`模块的写法,避免使用`module`函数,而是返回个表。 修改后的代码(test.lua): ```lua -- 将原来的module方式改为返回个模块表 local M = {} -- 尝试加载uci模块 local uci = require "luci.model.uci" -- 定义函数 function M.test() return 1 end return M ``` 然后,我们使用相同的命令测试: lua -e 'print(require("luci.model.test").test())' 如果这样修改后问题解决,说明是原来的`module`函数使用导致的环境问题。 如果问题依旧,那么可能是`luci.model.uci`模块本身的问题,需要检查它的代码。 但是,由于错误信息指向了`uci.lua`的第27行,我们可能需要查看该文件。在OpenWrt的LuCI中,`uci.lua`文件通常位于`/usr/lib/lua/luci/model/uci.lua`(具体路径可能根据安装位置不同而不同)。我们可以检查该文件的第27行,看看是否有语法错误或者加载其他模块的代码。 常见的情况是,在`uci.lua`中可能也尝试加载了`luci.model.test`模块(或者间接加载),从而形成循环依赖。在这种情况下,我们需要打破循环依赖,例如将公共部分提取到第三个模块。 由于我们无法直接修改`uci`模块(它是LuCI的核心模块),所以如果我们发现确实是循环依赖,那么可能需要重新组织我们的代码,避免在`luci.model.test`中加载`uci`模块,或者将需要`uci`的功能移到另个模块中。 但是,在没有更多信息的情况下,我们首先尝试修改我们自己的模块写法。 因此,我建议将`luci.model.test`模块改为返回表的写法,并重新测试。 如果问题仍然存在,我们需要进步调试。 另外,注意错误信息中提到的`./uci.lua:27`,这可能是由于当前目录下有个名为`uci.lua`的文件?因为`require "luci.model.uci"`通常会搜索`luci/model/uci.lua`,但如果当前目录有个`uci.lua`,它可能会被首先找到(因为当前目录在package.path中通常排在前面)。所以,请确保当前目录下没有名为`uci.lua`的文件。 总结解决方案: 1. 修改模块定义方式,避免使用`module`函数。 2. 检查是否有重名的`uci.lua`文件在搜索路径的前面(如当前目录)。 3. 单独测试`luci.model.uci`模块的加载。 下面我们给出修改后的代码: </think> 根据错误信息`loop or previous error loading module 'uci'`,这表明在加载`uci`模块时出现了循环依赖或模块加载错误。以下是详细分析和解决方案: ### 问题原因: 1. **循环依赖**:`luci.model.uci`模块在加载过程中可能间接引用了当前模块`luci.model.test`,形成了循环依赖。 2. **模块加载冲突**:Lua的`module()`函数会改变当前模块的环境,可能影响后续`require`的行为。 3. **路径问题**:`luci.model.uci`模块可能未正确安装或路径配置错误。 ### 解决方案: #### 1. 避免使用`module()`函数 使用更现代的模块定义方式(返回表)替换`module()`,避免环境污染: ```lua -- 修改后的 luci/model/test.lua local M = {} -- 延迟加载 uci 模块(只在需要时加载) function M.test() local uci = require "luci.model.uci" return 1 end return M ``` #### 2. 检查模块安装路径 确保`uci`模块正确安装在Lua路径中: ```bash # 检查 uci.lua 文件是否存在 find / -name 'uci.lua' 2>/dev/null # 示例输出(路径应包含在package.path中): # /usr/lib/lua/luci/model/uci.lua ``` #### 3. 验证`uci`模块独立性 单独测试`uci`模块是否能加载: ```bash lua -e 'print(require("luci.model.uci"))' ``` 若报错,说明`uci`模块本身有问题,需检查其依赖或安装。 #### 4. 调试模块加载过程 在脚本中加入调试信息: ```lua local M = {} print("==== Loading test module ====") function M.test() print("==== Entering test function ====") local uci = require "luci.model.uci" print("==== UCI loaded successfully ====") return 1 end return M ``` 运行观察输出: ```bash lua -e 'print(require("luci.model.test").test())' ``` ### 修复后代码示例: ```lua -- luci/model/test.lua local M = {} function M.test() -- 延迟加载避免循环依赖 local uci = require "luci.model.uci" -- 实际使用uci模块的代码 return uci and 1 or 0 end return M ``` ### 关键说明: - **延迟加载**:在函数内部`require`而非模块顶部,打破循环依赖链。 - **避免`module()`**:该函数在Lua 5.1后不推荐使用,它会改变全局环境。 - **路径验证**:确保`package.path`包含`/usr/lib/lua/?.lua`等标准路径。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值