🐶 Sync 2025-11-02 14:26:26

This commit is contained in:
actions-user
2025-11-02 14:26:26 +08:00
parent 64bcc56c2a
commit ac011db799
1557 changed files with 746465 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2021 jjm2473
]]--
require "luci.util"
module("luci.controller.admin.ota",package.seeall)
function index()
if nixio.fs.access("/rom/bin/ota") then
entry({"admin", "system", "ota"}, call("action_ota"), _("OTA"), 69)
entry({"admin", "system", "ota", "check"}, post("action_check"))
entry({"admin", "system", "ota", "download"}, post("action_download"))
entry({"admin", "system", "ota", "progress"}, call("action_progress"))
entry({"admin", "system", "ota", "cancel"}, post("action_cancel"))
end
end
local function ota_exec(cmd)
local nixio = require "nixio"
local os = require "os"
local fs = require "nixio.fs"
local rshift = nixio.bit.rshift
local oflags = nixio.open_flags("wronly", "creat")
local lock, code, msg = nixio.open("/var/lock/ota_api.lock", oflags)
if not lock then
return 255, "", "Open stdio lock failed: " .. msg
end
-- Acquire lock
local stat, code, msg = lock:lock("tlock")
if not stat then
lock:close()
return 255, "", "Lock stdio failed: " .. msg
end
local r = os.execute(cmd .. " >/var/log/ota.stdout 2>/var/log/ota.stderr")
local e = fs.readfile("/var/log/ota.stderr")
local o = fs.readfile("/var/log/ota.stdout")
fs.unlink("/var/log/ota.stderr")
fs.unlink("/var/log/ota.stdout")
lock:lock("ulock")
lock:close()
e = e or ""
if r == 256 and e == "" then
e = "os.execute failed, is /var/log full or not existed?"
end
return rshift(r, 8), o or "", e or ""
end
local function image_supported(image)
return (os.execute("sysupgrade -T %q >/dev/null" % image) == 0)
end
function action_ota()
local image_tmp = "/tmp/firmware.img"
local http = require "luci.http"
if http.formvalue("apply") == "1" then
if not image_supported(image_tmp) then
luci.template.render("admin_system/ota", {image_invalid = true})
return
end
local keep = (http.formvalue("keep") == "1") and "" or "-n"
luci.template.render("admin_system/ota_flashing", {
title = luci.i18n.translate("Flashing…"),
msg = luci.i18n.translate("The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
addr = (#keep > 0) and "10.0.0.1" or nil
})
fork_exec("sleep 1; killall dropbear uhttpd nginx; sleep 1; sync; /sbin/sysupgrade %s %q" %{ keep, image_tmp })
else
luci.template.render("admin_system/ota")
end
end
function action_check()
local r,o,e = ota_exec("ota check")
local ret = {
code = 500,
msg = "Unknown"
}
if r == 0 then
ret.code = 0
ret.msg = o
elseif r == 1 then
ret.code = 1
ret.msg = "Already the latest firmware"
else
ret.code = 500
ret.msg = e
end
luci.http.prepare_content("application/json")
luci.http.write_json(ret)
end
function action_download()
local r,o,e = ota_exec("ota download")
local ret = {
code = 500,
msg = "Unknown"
}
if r == 0 then
ret.code = 0
ret.msg = ""
else
ret.code = 500
ret.msg = e
end
luci.http.prepare_content("application/json")
luci.http.write_json(ret)
end
function action_progress()
local r,o,e = ota_exec("ota progress")
local ret = {
code = 500,
msg = "Unknown"
}
if r == 0 then
ret.code = 0
ret.msg = "done"
elseif r == 1 or r == 2 then
ret.code = r
ret.msg = o
else
ret.code = 500
ret.msg = e
end
luci.http.prepare_content("application/json")
luci.http.write_json(ret)
end
function action_cancel()
local r,o,e = ota_exec("ota cancel")
local ret = {
code = 500,
msg = "Unknown"
}
if r == 0 then
ret.code = 0
ret.msg = "ok"
else
ret.code = 500
ret.msg = e
end
luci.http.prepare_content("application/json")
luci.http.write_json(ret)
end
function fork_exec(command)
local pid = nixio.fork()
if pid > 0 then
return
elseif pid == 0 then
-- change to root dir
nixio.chdir("/")
-- patch stdin, out, err to /dev/null
local null = nixio.open("/dev/null", "w+")
if null then
nixio.dup(null, nixio.stderr)
nixio.dup(null, nixio.stdout)
nixio.dup(null, nixio.stdin)
if null:fileno() > 2 then
null:close()
end
end
-- replace with target command
nixio.exec("/bin/sh", "-c", command)
end
end

View File

@@ -0,0 +1,218 @@
<%#
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<%
local fs = require "nixio.fs"
-%>
<h2 name="content"><%:OTA%></h2>
<style>
.state-ctl .state {
display: none;
padding: 0 !important;
margin: 0 !important;
border: 0 !important;
}
.state-ctl.state-ctl-unchecked .state.state-unchecked,
.state-ctl.state-ctl-checked .state.state-checked,
.state-ctl.state-ctl-downloading .state.state-downloading,
.state-ctl.state-ctl-downloaded .state.state-downloaded
{
display: inherit;
}
</style>
<fieldset class="cbi-section">
<fieldset class="cbi-section state-ctl state-ctl-unchecked">
<legend><%:Upgrade firmware On the Air%></legend>
<div class="cbi-section-descr"><%:Check and upgrade firmware from the Internet%></div>
<% if image_invalid then %>
<div class="cbi-section-error"><%:The image file does not contain a supported format. Maybe try again later.%></div>
<% end %>
<div class="cbi-section-node">
<div class="state state-unchecked">
<form>
<div class="cbi-value">
<label class="cbi-value-title" id="check_result"></label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-reload" type="button" name="check" value="<%:Check update%>" />
</div>
</div>
</form>
</div>
<div class="state state-checked">
<form>
<div class="cbi-value">
<label class="cbi-value-title" id="download_result"><%:Found new firmware%></label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-apply" type="button" name="download" value="<%:Download firmware%>" />
</div>
</div>
</form>
</div>
<div class="state state-downloading">
<form>
<div class="cbi-value">
<label class="cbi-value-title" id="download_progress">0%</label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-reset" type="button" name="cancel" value="<%:Cancel download%>" />
</div>
</div>
</form>
</div>
<div class="state state-downloaded">
<% if fs.access("/usr/lib/lua/luci/controller/admin/system.lua") then %>
<form method="post" action="<%=url('admin/system/flashops/sysupgrade')%>" enctype="multipart/form-data">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="step" value="1" />
<div class="cbi-value">
<label class="cbi-value-title"><%:Firmware downloaded%></label>
<div class="cbi-value-field">
<input type="submit" class="cbi-button cbi-input-apply" value="<%:Flash image...%>" />
</div>
</div>
</form>
<% else %>
<form method="post" action="<%=url('admin/system/ota')%>">
<input type="hidden" name="apply" value="1" />
<input type="hidden" name="token" value="<%=token%>" />
<div class="cbi-value">
<label class="cbi-value-title" for="keep"><%:Keep settings and retain the current configuration%></label>
<div class="cbi-value-field">
<input type="checkbox" name="keep" value="1" id="keep" checked="checked" />
</div>
</div>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title"><%:Firmware downloaded%></label>
<div class="cbi-value-field">
<input type="submit" class="cbi-button cbi-input-apply" value="<%:Flash image...%>" />
</div>
</div>
</form>
<% end %>
</div>
</div>
<div class="state state-checked state-downloading state-downloaded">
<div class="cbi-section-descr">
<h2><%:The latest firmware%>:</h2>
<div id="upgrade_log"></div>
</div>
</div>
</fieldset>
<script>
(function(){
var csrfToken = "<%=token%>";
var check = document.querySelector('input[name="check"]');
var download = document.querySelector('input[name="download"]');
var cancel = document.querySelector('input[name="cancel"]');
var state_ctl = document.querySelector('.state-ctl');
var check_result = document.querySelector('#check_result');
var download_result = document.querySelector('#download_result');
var download_progress = document.querySelector('#download_progress');
var upgrade_log = document.querySelector('#upgrade_log');
var xhr_post = function(url, data, cb) {
data = data || {};
data.token = '<%=token%>';
new XHR().post(url, data, function(x, d){
cb && cb(x, x.status==200?JSON.parse(x.responseText):{code:500,msg:x.responseText});
});
};
var state_switch = function(from, to) {
state_ctl.classList.remove("state-ctl-" + from);
state_ctl.classList.add("state-ctl-" + to);
};
check.onclick = function(){
check.disabled = 'disabled';
check_result.innerText = "<%:Checking...%>";
xhr_post("<%=url('admin/system/ota/check')%>", {}, function(x, d){
check.disabled = undefined;
switch(d.code){
case 0:
check_result.innerText = "";
upgrade_log.innerHTML = d.msg;
state_switch("unchecked", "checked");
break;
case 1:
check_result.innerText = "<%:Already the latest firmware%>";
break;
default:
check_result.innerText = "<%:Check failed%>";
alert("<%:Check failed%>:\n"+d.msg);
}
});
};
var refresh_download_progress_paused = false;
var refresh_download_progress_timer = null;
var refresh_download_progress = function() {
if (refresh_download_progress_paused) {
refresh_download_progress_timer = setTimeout(refresh_download_progress, 500);
return;
}
XHR.get("<%=url('admin/system/ota/progress')%>", {}, function(x, d){
refresh_download_progress_timer = null;
switch(d.code){
case 0:
download_progress.innerText = "";
state_switch("downloading", "downloaded");
break;
case 1:
// if (d.msg.startsWith('#')) {
if (/^[0-9]/.test(d.msg)) {
if (!refresh_download_progress_paused)
cancel.disabled = undefined;
download_progress.innerText = "<%:Downloading%>: "+d.msg;
} else {
if (!refresh_download_progress_paused)
cancel.disabled = 'disabled';
download_progress.innerText = d.msg;
}
refresh_download_progress_timer = setTimeout(refresh_download_progress, 500);
break;
case 2:
download_result.innerText = "<%:Download canceled%>";
state_switch("downloading", "checked");
break;
default:
download_result.innerText = "<%:Download failed%>";
state_switch("downloading", "checked");
alert("<%:Download failed%>:"+d.msg);
}
});
};
download.onclick = function(){
download.disabled = 'disabled';
xhr_post("<%=url('admin/system/ota/download')%>", {}, function(x, d){
download.disabled = undefined;
switch(d.code){
case 0:
download_progress.innerText = "<%:Downloading%>: ...";
cancel.disabled = 'disabled';
state_switch("checked", "downloading");
refresh_download_progress_timer = setTimeout(refresh_download_progress, 500);
break;
default:
alert("<%:Download failed%>:"+d.msg);
}
});
};
cancel.onclick = function() {
cancel.disabled = 'disabled';
refresh_download_progress_paused = true;
xhr_post("<%=url('admin/system/ota/cancel')%>", {}, function(x, d){
refresh_download_progress_paused = false;
});
};
})();
</script>
</fieldset>
<%+footer%>

File diff suppressed because one or more lines are too long