openwrt luci web分析

openwrt luci web分析

来源 https://www.jianshu.com/p/596485f95cf2php

 

www/cbi-bin/luci

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

run方法的主要任务就是在安全的环境中打开开始页面(登陆页面),在run中,最主要的功能仍是在dispatch.lua中完成。html

LUCI的MVC

用户管理:
在luci的官方网站说明了luci是一个MVC架构的框架,这个MVC作的可扩展性很好,能够彻底的统一的写本身的html网页,并且他对shell的支持至关的到位,(由于luci是lua写的,lua是C的儿子嘛,与shell是兄弟)。
在登陆界面用户名的选择很重要,luci是一个单用户框架,公用的模块放置在/luci/controller/下面,各个用户的模块放置在/luci/controller/下面对应的文件夹里面,好比 admin登陆,最终的页面只显示/luci/controller/admin下面的菜单。这样既有效的管理了不一样管理员的权限。web

controller

controller主要用于控制页面按钮位置,以及调用的功能.首先来编辑这个文件.shell

$vim ~/temp/addtest/files/usr/lib/lua/luci/controller/addtest.lua

代码以下:vim

module("luci.controller.addtest",package.seeall) function index() entry({"admin","system","addtest"},alias("admin","system","addtest","set"),_("AddTest"),99).index=true entry({"admin","system","addtest","set"},cbi("addtest"),_("Set"),1) entry({"admin","system","addtest","info"},call("action_info"),_("Info"),2) end function action_info() if not nixio.fs.access("/tmp/addtest") then return end local info = nixio.fs.readfile("/tmp/addtest") luci.template.render("addtest_info",{info=info}) end 

格式模板:api

module("luci.controller.控制器名", package.seeall) function index() entry(路径, 调用目标, _("显示名称"), 显示顺序) end 

这个脚本文件能够分为3块:第1行,37行,916行
第1行
说明了模块的名称,本文在controller目录下建立了addtest.lua文件,将模板中的控制器名替换为addtest便可.
第3行
第3~7行定义按钮的位置,调用的功能,显示名称.其中第3行和第7行是固定的模板格式,不须要修改
第4行
entry表示添加新的模块.
第一个参数{"admin","system","addtest"}表示按钮的位置.admin表示咱们这个功能只有以管理员身份登陆页面才能够看到.system表示一级菜单名,addtest则是一级菜单下的子菜单.
第二个参数alias("admin","system","addtest","set")表示调用的功能.这个按钮没有独立的功能,而是将它关联到它的下一级子菜单set.
第三个参数_("AddTest")表示显示名称,可选.若是页面按钮想作成中文,能够在这里设置.
第四个参数99表示显示顺序的优先级,Luci根据这个值为同一父菜单的全部子菜单排序.
第5行
第一个参数{"admin","system","addtest","set"}表示在addtest下再增长一个子选项set.
第二个参数cbi("addtest")表示调用cbi模块,这里将会调用到/usr/lib/lua/luci/model/cbi/addtest.lua
第6行
第二个参数call("action_info")表示执行指定方法,这里将会调用咱们下面写的acttion_info函数.
备注
关于entry第二个参数调用目标.咱们还有一个template没有涉及,它表示访问指定页面.好比template(addtest_info)将会直接访问/usr/lib/lua/luci/view/addtest_info.htm.
9~16行
这里使用lua语言调用nixio接口写了一个简单的函数,首先判断文件是否存在,而后读取其中的内容赋值给变量info,最后访问指定页面/usr/lib/lua/luci/view/addtest_info.htm,同时将变量info传递过去.
luci接口手册
nixio接口手册缓存

uci

UCI是openwrt的配置管理机制,它将配置统一放到/etc/config文件夹下.详细地介绍请参考这里.
下面来编辑这个文件安全

$vim ~/temp/addtest/files/etc/config/addtest 

代码以下:ruby

config arguments
    option interval '' option content '' 

Section开始语法: config '类型' '名字'
参数定义语法: option '键' '值'
列表定义语法: list '集合名字' '值'bash

简单解释下,咱们在/etc/config下新建一个名为addtest的配置文件,其中类型为arguments,名字省略.有两个键,一个名为interval用来存时间间隔.一个名为content用来存准备周期性输入的内容.

model

在controller提到cbi会调用到model文件夹中的addtest.lua文件.下面来编辑它

$vim ~/temp/addtest/files/usr/lib/lua/luci/model/cbi/addtest.lua 

代码以下:

m=Map("addtest",translate("Luci practice"),translate("fat cheng's test"))

s=m:section(TypedSection,"arguments","")
s.addremove=true
s.anonymous=false

s:option(Flag,"enable",translate("Enable"))
s:option(Value,"interval",translate("Interval"))
s:option(Value,"content",translate("Content"))

local apply=luci.http.formvalue("cbi.apply")
if apply then
    io.popen("/etc/init.d/addtestd restart")
end

return m

来解释下这个文件
第1行
模板m = Map("配置文件文件名", "配置页面标题", "配置页面说明")
第一个参数:上一步咱们新建配置文件/etc/config/addtest.这里就是创建与配置文件的联系.
第二,三两个参数,则是页面的主标题和副标题.还不清楚的话,翻上去看看最终效果图,看看它们在哪里.
第3行
在一个配置文件中可能有不少Section,因此咱们须要建立与配置文件中咱们想要的Section的联系.
有两种方式能够选择:NamedSection(name,type,title,description)和TypedSection(type,title,description),前者根据配置文件中的Section名,然后者根据配置文件中的Section类型.咱们选用了第二种.
第4行
设定不容许增长或删除Section
第5行
设定显示Section的名称,这里建议你能够试试设定为true,看看会发生什么.
7~9行
接着则是创建与Section中的option之间的联系.模板s:option(交互形式,option键值,显示名称).
第一个参数:常见的交互形式有Value(文本框),ListValue(下拉框),Flag(选择框).,不知道为啥我打不开官方文档,这里也能够参考
第二个参数表示在配置文件中的option的键值
第三个参数表示,你但愿在页面上呈现的名称.
建立后开发者无需考虑读取以及写入配置文件的问题,系统会自动处理.
11~14行
系统会为咱们在页面上自动建立一些按钮Save&Apply,Save,Reset.咱们仅仅将配置写入/etc/config下对应的文件是不够的,咱们还但愿能够根据这个配置进行一些操做.
这部分代码的做用是,当你按下页面的apply按钮后,至关于在串口shell下输入/etc/init.d/addtestd restart

init.d

上面已经能够读写配置了,怎么根据配置来进行操做呢?来编辑~/temp/addtest/files/etc/init.d/addtestd这个文件.
代码以下:

#!/bin/sh /etc/rc.common
START=50

run_addtest()
{
    local enable
    config_get_bool enable $1 enable

    if [ $enable ]; then
        local interval
        local content
        config_get interval $1 interval
        config_get content $1 content

        addtest $interval $content           
    fi
}

start()
{
    config_load addtest
    config_foreach run_addtest arguments
}

stop()
{
    result=`pidof addtest`
    kill -9 $result
    echo "addtest has stoped"
}

第1行
Linux 系统根据 “#!” 及该字串后面的信息肯定该文件的类型,表示这个文件须要由/bin/sh和/etc/rc.common来解释执行.
第2行
表示启动的优先级,这里暂时用不到
4~17行
是一个函数,主要做用是读取/etc/config/addtest中的内容,而后根据是否打开开关在第15行将配置传递给可执行文件addtest,由它根据配置执行指定的操做.
读取配置的方法,我强烈推荐你阅读官方文档,精炼而简洁.
获取布尔值类型:config_get_bool 变量名 Section名 Section参数名
获取变量值:config_get 变量名 Section名 Section参数名
19~23行
对应于/etc/init.d/addtestd start.首先使用config_load 配置文件名的方法载入配置文件,而后使用config_foreach 遍历函数名 Section类型的方法,遍历配置文件中的Section.
25~30行
对应于/etc/init.d/addtestd stop.找到addtest这个进程的进程号,而后杀死它
备注
前面提到的/etc/init.d/addtestd restart中的restart命令,在/etc/rc.common进行了定义,简单来说就是先执行了stop命令,再执行start命令.
最后务必执行$sudo chmod 755 ~/temp/addtest/files/etc/init.d/addtestd.

src

前面提到run_addtest调用可执行文件addtest,如今咱们编辑这部份内容

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int index;
    for(index=0; index<10; index++)
    {
        FILE *fp=fopen("/tmp/addtest","at");
        system("date >> /tmp/addtest");
        fprintf(fp, "%s\n", argv[2]);
        fclose(fp);
        printf("interval=%d\n",atoi(argv[1]));
        sleep(  atoi(argv[1]) );
    }
    return 0;
}

经过这个可执行文件,咱们周期性地将时间戳和内容写入了/tmp/addtest文件.
最后咱们写一个简单的Makefile:

$vim $vim ~/temp/addtest/files/src/Makefile
addtest : addtest.o $(CC) addtest.o -o addtest addtest.o : addtest.c $(CC) -c addtest.c clean : rm *.o addtest 

View

前面已经根据配置将指定的内容周期性地写入了/tmp/addtest.在controller中咱们的函数action_info读取了/tmp/addtest中的内容并访问指定页面/usr/lib/lua/luci/view/addtest_info.htm,同时将读取的内容经过变量info传递过去.
下面咱们来编辑这个页面,

$vim ~/temp/addtest/files/usr/lib/lua/luci/view/addtest_info.htm
<%+header%>
<h2><a id="content" name="content"><%:Addtest Info%></a></h2> <div id="content_addtest_info"> <textarea readonly="readonly" wrap="off" rows="<%=info:cmatch("\n")+2%>" id="info"><%=info:pcdata()%></textarea> </div> <%+footer%> 

Makefile

用一个Makefie文件将它们打包生成一个ipk文件.

include $(TOPDIR)/rules.mk PKG_NAME:=addtest PKG_VERSION=1.0 PKG_RELEASE:=1 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk define Package/addtest SECTION:=utils CATEGORY:=Utilities TITLE:=Addtest--print something to /var/addtest endef define Package/addtest/description It's a test,print something to /var/addtest cyclicaliy endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Package/addtest/postinst #!/bin/sh rm -rf /tmp/luci* endef define Build/Configure endef define Build/Compile $(call Build/Compile/Default) endef define Package/$(PKG_NAME)/install $(CP) ./files/* $(1)/ $(INSTALL_DIR) $(1)/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/addtest $(1)/bin endef $(eval $(call BuildPackage,$(PKG_NAME)))

 

================ End

相关文章
相关标签/搜索