openwrt luci web分析

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

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中完成。

LUCI的MVC

用户管理:
在luci的官方网站说明了luci是一个MVC架构的框架,这个MVC做的可扩展性很好,可以完全的统一的写自己的html网页,而且他对shell的支持相当的到位,(因为luci是lua写的,lua是C的儿子嘛,与shell是兄弟)。
在登录界面用户名的选择很重要,luci是一个单用户框架,公用的模块放置在/luci/controller/下面,各个用户的模块放置在/luci/controller/下面对应的文件夹里面,比如 admin登录,最终的页面只显示/luci/controller/admin下面的菜单。这样既有效的管理了不同管理员的权限。

controller

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

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

代码如下:

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

格式模板:

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

代码如下:

config arguments
option interval ''
option content ''

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

简单解释下,我们在/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

openwrt luci web分析的更多相关文章

  1. Openwrt LuCI模块练习详细步骤

    前言 又到了成胖子^_^每周一博的时间了.最近在学习openwrt luci方面的知识,为了贯穿整个知识体系,练习题目为: 通过页面配置周期性地往/tmp/addtest文件写入内容和时间戳 1.在w ...

  2. 【玩转开源】BananaPi R2 —— 第四篇 Openwrt Luci 初探

    什么是Luci呢?先直观的感受一下,打开web浏览器,输入R2的网关地址,然后出现了一个web登录界面,这个就是Openwrt Luci的应用. 那么到底什么是Luci呢?在这里我先给大家一个公式:L ...

  3. openwrt: Makefile 框架分析

    openwrt: Makefile 框架分析 原文链接:blog.chinaunix.net/uid-26675482-id-4704952.html 本篇的主要目的是想通过分析Makefile,了解 ...

  4. 关于openwrt使用web升级提示固件版本不对的处理方法

    参考资料:https://blog.csdn.net/caoshunxin01/article/details/79355602 当openwrt使用web升级提示固件版本不对: The upload ...

  5. Luci流程分析(openwrt下)

    1. 页面请求: 1.1. 代码结构 在openwrt文件系统中,lua语言的代码不要编译,类似一种脚本语言被执行,还有一些uhttpd服务器的主目录,它们是: /www/index.html cgi ...

  6. openwrt u-boot_mod 代码分析

    u-boot_mod 是具有web 浏览器的uboot,也就是传说中的不死uboot,这里的不死指的是不管怎么刷firmware 都可以方便更换firmware,而不是uboot本身就是不死的. 这里 ...

  7. ubuntu编译openwrt前端web界面

    openwrt是由Cisco放出源代码的开放无线路由平台.由于是基于linux内核,所以可以将很多linux平台下的软件移植到此平台下,然后让无线路由拥有很多意想不到的功能,例如拿来做BT下载器,音乐 ...

  8. 【玩转开源】BananaPi R2 —— 第二篇 Openwrt 网口配置分析

    上次和大家分享了如何烧录和安装Openwrt到BananaPi R2,运行Openwrt的R2目前就具备路由器的功能了,这次我们来看看R2运行Openwrt的性能如何,同时也会讲解一些常用的网络知识. ...

  9. 读了这篇文章,你将变身web分析大师

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由shirishiyue发表于云+社区专栏 1.工具介绍 ​ 这是一个非常详细且专业的web页面性能分析工具,而且开源的!如果你打不开其 ...

随机推荐

  1. React_03_ECMAScript6

    1.ES6解构赋值 1.1.解构赋值概述 解构赋值是对赋值运算符的扩展. 它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值.在代码书写上简洁且易读,语义更加清晰明了:也方便了复杂对象中数 ...

  2. python 安装离线库

    (起因:报错找不到一个module,百度也找不到这个module,机智如我找宁博翻墙看怎么解决,毕竟是歪果仁的代码嘛,果真就在git找到了这个module哈哈哈哈机智如我!) 方法: 进入命令行窗口, ...

  3. 2019暑假Java学习笔记(一)

    目录 基础语法(上) HelloWorld 变量 常量 数据类型 整数 浮点数 char类型 boolean类型 String 计算字符串长度 字符串比较 字符串连接 charAt()方法 字符串常用 ...

  4. 第06组 Alpha冲刺(4/4)

    队名:福大帮 组长博客链接:https://www.cnblogs.com/mhq-mhq/p/11913386.html 作业博客 :https://edu.cnblogs.com/campus/f ...

  5. ActionFilter、IAuthorizationFilter 权限验证重定向跳转到其它页面

    方法一: public class IsAllowAttribute: ActionFilterAttribute { public override void OnActionExecuting(A ...

  6. Java_jdbc 基础笔记之十 数据库连接 (ResultSetMetaData 类)

    ResultSetMetaData 类 调用ResultSet 的getMetaData()方法得到ResultSetMetaData 类对象: 可用于获取关于 ResultSet 对象中列的类型和属 ...

  7. activiti 术语 国际化文件

    activiti-explorer editor-app 国际化文件 - 大强的博客 - CSDN博客https://blog.csdn.net/daqiang012/article/details/ ...

  8. [转]Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释

    原文地址:https://blog.csdn.net/qq_27093465/article/details/78544505 遇到这个 Java Serializable 序列化这个接口,我们可能会 ...

  9. openresty开发系列30--openresty中使用全局缓存

    openresty开发系列30--openresty中使用全局缓存 Nginx全局内存---本地缓存 使用过如Java的朋友可能知道如Ehcache等这种进程内本地缓存.Nginx是一个Master进 ...

  10. Appium脚本(2):元素检测

    场景: 有的按钮在第一次打开时显示,之后就不显示了,如更新提示.特性介绍等,面对这样的场景写了如下脚本,增加脚本的复用性. no_element_exception_2.py from appium ...