luci頁面“save&apply”的實現分析

轉自:https://blog.csdn.net/qq_19004627/article/details/80364249

頁面上配置的“保存&應用”功能的實現:

最終調用到/etc/config/ucitrack的配置文件。


例如配置無線時,對應ucitrack配置文件中的
config network
    option init network
    list affects dhcp
    list affects radvd

config wireless
    list affects network   // 更改無線參數時,會影響network相關的配置,會重新調用其初始化腳本initscript
段部分

問題一、那麼如何添加到ucitrack配置文件中的呢?
答:是通過uci-defaults手動添加的。
搜索一下可以發現:
./feeds/packages/net/mwan3-luci/files/etc/uci-defaults
./feeds/oldpackages/net/wing/files/etc/uci-defaults
./feeds/luci/i18n/portuguese-brazilian/root/etc/uci-defaults
./feeds/luci/i18n/hungarian/root/etc/uci-defaults
./feeds/luci/i18n/ukrainian/root/etc/uci-defaults
./feeds/luci/i18n/hebrew/root/etc/uci-defaults
./feeds/luci/i18n/vietnamese/root/etc/uci-defaults
./feeds/luci/i18n/catalan/root/etc/uci-defaults
./feeds/luci/i18n/german/root/etc/uci-defaults
./feeds/luci/i18n/norwegian/root/etc/uci-defaults
./feeds/luci/i18n/english/root/etc/uci-defaults
./feeds/luci/i18n/chinese/root/etc/uci-defaults
./feeds/luci/i18n/greek/root/etc/uci-defaults
./feeds/luci/i18n/spanish/root/etc/uci-defaults
./feeds/luci/i18n/russian/root/etc/uci-defaults
./feeds/luci/i18n/polish/root/etc/uci-defaults
./feeds/luci/i18n/romanian/root/etc/uci-defaults
./feeds/luci/i18n/japanese/root/etc/uci-defaults
./feeds/luci/i18n/malay/root/etc/uci-defaults
./feeds/luci/i18n/french/root/etc/uci-defaults
./feeds/luci/i18n/swedish/root/etc/uci-defaults
./feeds/luci/i18n/italian/root/etc/uci-defaults
./feeds/luci/i18n/portuguese/root/etc/uci-defaults
./feeds/luci/themes/freifunk-bno/root/etc/uci-defaults
./feeds/luci/themes/openwrt/root/etc/uci-defaults
./feeds/luci/themes/bootstrap/root/etc/uci-defaults
./feeds/luci/themes/freifunk-generic/root/etc/uci-defaults
./feeds/luci/applications/luci-mmc-over-gpio/root/etc/uci-defaults
./feeds/luci/applications/luci-meshwizard/root/etc/uci-defaults
./feeds/luci/applications/luci-ushare/root/etc/uci-defaults
./feeds/luci/applications/luci-hwmqos/root/etc/uci-defaults
./feeds/luci/applications/luci-hd-idle/root/etc/uci-defaults
./feeds/luci/applications/luci-wshaper/root/etc/uci-defaults
./feeds/luci/applications/luci-p910nd/root/etc/uci-defaults
./feeds/luci/applications/luci-p2pblock/root/etc/uci-defaults
./feeds/luci/applications/luci-upnp/root/etc/uci-defaults
./feeds/luci/applications/luci-olsr/root/etc/uci-defaults
./feeds/luci/applications/luci-ser2net/root/etc/uci-defaults
./feeds/luci/applications/luci-polipo/root/etc/uci-defaults
./feeds/luci/applications/luci-statistics/root/etc/uci-defaults
./feeds/luci/applications/luci-backdoor/root/etc/uci-defaults
./feeds/luci/applications/luci-watchcat/root/etc/uci-defaults
./feeds/luci/applications/luci-ahcp/root/etc/uci-defaults
./feeds/luci/applications/luci-freifunk-diagnostics/root/etc/uci-defaults
./feeds/luci/applications/luci-vnstat/root/etc/uci-defaults
./feeds/luci/applications/luci-radvd/root/etc/uci-defaults
./feeds/luci/applications/luci-minidlna/root/etc/uci-defaults
./feeds/luci/applications/luci-transmission/root/etc/uci-defaults
./feeds/luci/applications/luci-asterisk/root/etc/uci-defaults
./feeds/luci/contrib/uci/hostfiles/bin/uci-defaults
./feeds/luci/contrib/package/freifunk-common/files/etc/uci-defaults
./feeds/luci/contrib/package/freifunk-gwcheck/root/etc/uci-defaults
./feeds/luci/contrib/package/freifunk-mapupdate/root/etc/uci-defaults
./feeds/luci/contrib/package/freifunk-policyrouting/files/etc/uci-defaults
./build_dir/target-mips_34kc_uClibc-0.9.33.2/root-ar71xx/etc/uci-defaults


查看 ./feeds/luci/i18n/chinese/root/etc/uci-defaults 文件,可以看到
文件內容如下:
#!/bin/sh
uci batch <<-EOF
   set luci.languages.zh_cn=chinese
   commit luci
EOF
利用uci命令,配置了兩條,
1) uci set luci.languages.zh_cn=chinese  配置了/etc/config/luci中的languages
2) uci commit luci 提交luci的更改
這個並沒有使用到ucitrack配置文件。

再看另外一個 ./feeds/luci/applications/luci-hwmqos/root/etc/uci-defaults 文件,可以看到
文件內容如下:
#!/bin/sh

#add service depends

uci -q batch <<-EOF >/dev/null
          delete ucitrack.@hwmqos[-1]
          add ucitrack hwmqos
          set ucitrack.@hwmqos[-1].init=hwmqos
          commit ucitrack   
EOF

rm -f /tmp/luci-indexcahe
exit 0
利用uci命令,批量配置瞭如下命令:
1)uci delete ucitrack.@hwmqos[-1]  刪除ucitrack配置文件中的hwmqos相關內容
2)uci add ucitrack hwmqos     增加ucitrack配置文件中的hwmqos
3)uci set ucitarck.@hwmqos[-1].init=hwmqos  相關的起始腳本(initscript)爲/etc/init.d/hwmqos
4)uci commit ucitrack  提交變更的文件


問題二、配置文件中的affects幹嘛用?
答:其實直接作用就是查找到相關的配置文件,再根據配置文件找到相關的起始腳本。當配置變更時,重新啓用腳本。

關於affects 在uci.lua中定義如下:

-- Return a list of initscripts affected by configuration changes.
-- 返回一些跟此配置更改相關的初始化腳本列表,
function Cursor._affected(self, configlist)
   configlist = type(configlist) == "table" and configlist or {configlist}

 local c = cursor()
 c:load("ucitrack")

 -- Resolve dependencies
 -- 分解依賴情況
 local reloadlist = {}

 local function _resolve_deps(name)
  local reload = {name}
  local deps = {}

  c:foreach("ucitrack", name,
   function(section)
    if section.affects then
     for i, aff in ipairs(section.affects) do
      deps[#deps+1] = aff         -- 將依賴的配置文件保存到deps數組中去(本例中是將network保存進去)
     end
    end
   end)

  for i, dep in ipairs(deps) do
   for j, add in ipairs(_resolve_deps(dep)) do
    reload[#reload+1] = add      -- 將所有依賴列表保存到一個數組reload中去(此處wireless只有一個依賴項affects,就是network)
   end
  end

  return reload
 end

 -- Collect initscripts
 -- 蒐集初始化腳本
 for j, config in ipairs(configlist) do
  for i, e in ipairs(_resolve_deps(config)) do
   if not util.contains(reloadlist, e) then   -- 檢測包reloadlist中是否含配置文件(cofig),若有包含,將其加入到reloadlist數組中
    reloadlist[#reloadlist+1] = e    
  end
 end

 return reloadlist
end 
 
 
問題三、html頁面“save&apply”如何實現的

通過調用"cbi.apply"最後調用到uci.lua腳本中的Cursor.apply.

其實現過程爲:

--- Applies UCI configuration changes
-- @param configlist  List of UCI configurations
-- @param command   Don't apply only return the command
function Cursor.apply(self, configlist, command)
 configlist = self:_affected(configlist)
 if command then
      return { "/sbin/luci-reload", unpack(configlist) }    // 調用luci-reload
 else
  return os.execute("/sbin/luci-reload %s >/dev/null 2>&1" % table.concat(configlist, " "))   // 調用luci-reload
 end
end

從函數apply可以看出,均是調用luci-reload。

 

問題四、luci-reload的實現過程,luci-reload是個shell腳本。

#!/bin/sh
. /lib/functions.sh

apply_config() {
 config_get init "$1" init              
 config_get exec "$1" exec
 config_get test "$1" test

 echo "$2" > "/var/run/luci-reload-status"     // 將狀態寫入到臨時文件中

 [ -n "$init" ] && reload_init "$2" "$init" "$test"   // 若ucitrack配置文件中init相關參數存在,則進行reload_init
 [ -n "$exec" ] && reload_exec "$2" "$exec" "$test"  // 若ucitrack配置文件中exec相關參數存在,則進行reload_exec

}

reload_exec() {
 local service="$1"
 local ok="$3"
 set -- $2
 local cmd="$1"; shift
 
 [ -x "$cmd" ] && {     // cmd具有可執行權限
  echo "Reloading $service... "
  ( $cmd "$@" ) 2>/dev/null 1>&2   // 執行 “cmd +所有參數”
  [ -n "$ok" -a "$?" != "$ok" ] && echo '!!! Failed to reload' $service '!!!'   // 若執行失敗,則打印消息
 }
}

reload_init() {
 [ -x /etc/init.d/$2 ] && /etc/init.d/$2 enabled && {
  echo "Reloading $1... "
  /etc/init.d/$2 reload >/dev/null 2>&1     // 執行腳本的 reload
  [ -n "$3" -a "$?" != "$3" ] && echo '!!! Failed to reload' $1 '!!!'    // 若執行失敗,則打印消息
  }
}

lock "/var/run/luci-reload"            // 1、防止多個線程同時調用luci-reload腳本,加鎖

config_load ucitrack                    // 2、加載配置文件/etc/config/ucitrack

for i in $*; do               
 config_foreach apply_config $i $i  // 3、遍歷所有相關配置和文件,進行重新初始化相關進程
done

rm -f "/var/run/luci-reload-status" // 刪除luci-reload-status狀態文件
lock -u "/var/run/luci-reload"         // 解鎖


 ===========================================

2017年1月16日補充:

整個實現過程如下:

(1)頁面上有"Save & Apply"的功能選項的頁面,在單擊按鈕時,會調用到"changes.htm"頁面。頁面中關於按鈕定義如下:

        <form class="inline" method="get" action="<%=controller%>/admin/uci/saveapply">
             <input type="hidden" name="redir" value="<%=pcdata(luci.http.formvalue("redir"))%>" />
           <input class="cbi-button cbi-button-save" type="submit" value="<%:Save & Apply%>" />
      </form>

      對應的動作爲 ../admin/uci/saveapply

(2)打開對應的 uci.lua文件,可以看到 saveapply對應的定義如下:

         entry({"admin", "uci", "saveapply"}, call("action_apply"), _("Save &#38; Apply"), 10).query = {redir=redir}

         action_apply()函數實現如下:

        

    function action_apply()
       local path = luci.dispatcher.context.path
       local uci = luci.model.uci.cursor()
       local changes = uci:changes()
       local reload = {}

     -- Collect files to be applied and commit changes
       for r, tbl in pairs(changes) do
          table.insert(reload, r)
          if path[#path] ~= "apply" then
             uci:load(r)
             uci:commit(r)
             uci:unload(r)
          end
        end

     luci.template.render("admin_uci/apply", {                    跳轉到界面apply.htm
        changes = next(changes) and changes,
        configs = reload
      })
    end

 (3)apply.htm中主要內容如下:

        

   <%+cbi/apply_xhr%>              添加頁面 apply_xhr.htm
   <%+admin_uci/changelog%>           添加頁面 changelog.htm

   <%- cbi_apply_xhr('uci-apply', configs) -%>    去掉調用腳本cbi_apply_xhr

(4)查看 apply_xhr.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章