openwrt luci web解析

本文介绍了一台搭载newifi mini硬件、基于Pandorabox固件的路由器,其LUCI主题为lafite。通过WinSCP和SecurCRT串口登录,分析了LUCI的工作原理。当访问192.168.1.1时,CGI进程启动lua的cgi.lua文件,进而调用luci控制器和视图文件。在dispatcher.lua中,luci读取配置并解析主题,使用lafite主题的lua脚本。在lafite.lua中,通过entry函数注册各个模块,实现界面展示和功能交互。

路由器:newifi mini
硬件信息:mt7620a +mt7612e+128M DDR+16M flash
固件: Pandorabox
luci theme:lafite
主界面:
这里写图片描述

winSCP登录
securieCRT 串口登录

/www/index.html:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="refresh" content="0; URL=/cgi-bin/luci" />
</head>
<body style="background-color: white">
<a style="color: black; font-family: arial, helvetica, sans-serif;" href="/cgi-bin/luci">LuCI for PandoraBox</a>
</body>
</html>

在 uhttpd web server 中的 cgi-bin 目录下,运行 luci 文件(权限一般是 755 ) , luci 的代码如下:

#!/usr/bin/lua        #lua脚本,lua执行命令的路径
require "luci.cacheloader"     #导入 cacheloader 包
require "luci.sgi.cgi"         # 导入 sgi.cgi 包
luci.dispatcher.indexcache = "/tmp/luci-indexcache"     #cache 缓存路径地址
luci.sgi.cgi.run()         #执行run方法,此方法位于 /usr/lib/lua/luci/sgi/cgi.lua中

找到lcgi.lua运行文件, /usr/lib/lua/luci/sgi/cgi.lua :

exectime=os.clock()
module("luci.sgi.cgi",package.seeall)
local a=require("luci.ltn12")
require("nixio.util")
require("luci.http")
require("luci.sys")
require("luci.dispatcher")
local function o(t,e)
e=e or 0
local a=a.BLOCKSIZE
return function()
if e<1 then
t:close()
return nil
else
local a=(e>a)and a or e
e=e-a
local e=t:read(a)
if not e then t:close()end
return e
end
end
end
function run()
local t=luci.http.Request(
luci.sys.getenv(),
o(io.stdin,tonumber(luci.sys.getenv("CONTENT_LENGTH"))),
a.sink.file(io.stderr)
)
local e=coroutine.create(luci.dispatcher.httpdispatch)    //开启协助线程---->调用/usr/lib/lua/luci/dispatcher.lua里的httpdispatch函数
local o=""
local i=true
while coroutine.status(e)~="dead"do
local n,e,t,a=coroutine.resume(e,t)
if not n then
print("Status: 500 Internal Server Error")
print("Content-Type: text/plain\n")
print(e)
break;
end
if i then
if e==1 then
io.write("Status: "..tostring(t).." "..a.."\r\n")
elseif e==2 then
o=o..t..": "..a.."\r\n"
elseif e==3 then
io.write(o)
io.write("\r\n")
elseif e==4 then
io.write(tostring(t or""))
elseif e==5 then
io.flush()
io.close()
i=false
elseif e==6 then
t:copyz(nixio.stdout,a)
t:close()
end
end
end
end

连接路由器,浏览器下输入192.168.1.1,转入192.168.1.1/cgi-bin/luci,转入登录页面,调用了/usr/lua/luci/controller/admin/index.html文件:

module("luci.controller.admin.index", package.seeall)

function index ()
    local root = node()
    if not root.target then
        root.target = alias("admin")
        root.index  = true
    end

    local page                 = node("admin")
    page.target                = firstchild()         //从dispatcher.lua调firstchild()
    page.title                 = _("Administration")
    page.order                 = 10
    page.sysauth               = "root"
    page.sysauth_authenticator = "htmlauth"     //从dispatcher.lua调htmlauth()
    page.ucidata               = true
    page.index                 = true

    -- Empty services menu to be populated by addons
    entry({"admin", "services"}, firstchild(), _("Services"), 40).index = true

    entry({"admin", "logout"}, call("action_logout"), _("Logout"), 90)
end

function action_logout ()
    local dsp = require "luci.dispatcher"
    local utl = require "luci.util"
    local sid = dsp.context.authsession

    if sid then
        utl.ubus("session", "destroy", { ubus_rpc_session = sid })

        luci.http.header("Set-Cookie", "sysauth=%s; expires=%s; path=%s/" %{
            sid, 'Thu, 01 Jan 1970 01:00:00 GMT', dsp.build_url()
        })
    end

    luci.http.redirect(dsp.build_url())
end

查看htmlauth()函数:

function authenticator.htmlauth(a,t,o)
local t=e.formvalue("luci_username")
local i=e.formvalue("luci_password")
if t and a(t,i)then
return t
end
require("luci.i18n")
require("luci.template")
context.path={}
e.status(403,"Forbidden")
luci.template.render("sysauth",{duser=o,fuser=t})
return false
end

在dispatcher.lua读取并解析了/etc/config下的luci配置,可以看到读取了theme:

if(t and t.index)or not i.notemplate then
local s=require("luci.template")
local t=i.mediaurlbase or luci.config.main.mediaurlbase
if not pcall(s.Template,"themes/%s/header"%n.basename(t))then
t=nil
for a,e in pairs(luci.config.themes)do
if a:sub(1,1)~="."and pcall(s.Template,
"themes/%s/header"%n.basename(e))then
t=e
end

使用了/usr/lib/lua/luci/viem/theme/lafite
查看/usr/lib/lua/luci/controller/admin/lafite.lua :

module("luci.controller.admin.lafite", package.seeall)

function index()
    local root = node()
    if not root.target then
        root.target = alias("lafite")
        root.index = true
    end

    function jump ()
        local uci = require("luci.model.uci").cursor()

        local themename = uci:get('luci', 'main', 'mediaurlbase') or nil

        if not themename then
            return template("jump")
        end

        themename = themename:match('([%da-zA-Z]*)$')
        if themename == 'lafite' then
            return template("jump")
        else
            local list = {}
            for _, v in ipairs(require('luci.fs').dir('/www/luci-static')) do
                if v ~= '.' and v ~= '..' then
                    list[#list+1] = v
                end
            end
            if #list > 2 then
                return alias("admin")
            end
        end
        return template("jump")
    end

    local page = entry({"lafite"}, jump(), nil, 0)
    page.sysauth = false
    page.ucidata = true
    page.index = true

    entry({"lafite", "change"}, call("action_change"), _("index"), 0)
end

function action_change()
    local sauth = require "luci.controller.api.user"
    local PBUtil = require "luci.pb.PBUtil"
    local code = PBUtil.message()

    local _apiAuth = sauth.checkApiAuth()
    if _apiAuth then return _apiAuth end

    local V = PBUtil.getFormValue({ 'change' })

    if not V.change then
        return code.miss('Change+')
    end
    if V.change ~= '0' and V.change ~= '1' then
        return code.error('Change+')
    end

    local themename = 'lafite'
    if V.change == '1' then
        local list = {}
        for _, v in ipairs(require('luci.fs').dir('/www/luci-static')) do
            if v ~= '.' and v ~= '..' then
                list[#list+1] = v
            end
        end
        if #list > 2 then
            for _, v in ipairs(list) do
                if v ~= 'lafite' and v ~= 'resources' then
                    themename = v
                end
            end
        end
    end

    PBUtil.setUCISection('luci', 'main', {
        mediaurlbase = '/luci-static/' .. themename
    })

    uci:commit('luci')

    return code.ok()
end

Luci则会calling /luci/admin/目录下的lafite.lua脚本。
模块入口文件lafite.lu中index()函数中,使用entry函数来完成每个模块函数的注册:

local page = entry({"lafite"}, jump(), nil, 0)

转入/www/web/

entry({"lafite", "change"}, call("action_change"), _("index"), 0)

change函数中加入了/usr/lib/lua/luci/pb/目录下文件

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值