來源 https://www.jianshu.com/p/596485f95cf2php
#!/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的官方網站說明了luci是一個MVC架構的框架,這個MVC作的可擴展性很好,能夠徹底的統一的寫本身的html網頁,並且他對shell的支持至關的到位,(由於luci是lua寫的,lua是C的兒子嘛,與shell是兄弟)。
在登陸界面用戶名的選擇很重要,luci是一個單用戶框架,公用的模塊放置在/luci/controller/下面,各個用戶的模塊放置在/luci/controller/下面對應的文件夾裏面,好比 admin登陸,最終的頁面只顯示/luci/controller/admin下面的菜單。這樣既有效的管理了不一樣管理員的權限。web
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是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用來存準備週期性輸入的內容.
在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
上面已經能夠讀寫配置了,怎麼根據配置來進行操做呢?來編輯~/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.
前面提到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
前面已經根據配置將指定的內容週期性地寫入了/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%>
用一個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