gluon/package/gluon-web-admin/luasrc/lib/gluon/config-mode/controller/admin/upgrade.lua
Tom Herbers 75ceb0d963
web-admin: ignore minor compat-version on upgrade (#2590)
This implements the same behavior as it is used in the autoupdater [1].

This is for example required to allow the manual installation of
firmware upgrades via the config mode on devices which where migrated
from swconfig to DSA. Otherwise the image will always be invalid.

[1] b804281664
2022-08-09 20:16:33 +02:00

143 lines
3.8 KiB
Lua

--[[
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
]]--
package 'gluon-web-admin'
local util = require 'gluon.util'
local unistd = require 'posix.unistd'
local file
local tmpfile = "/tmp/firmware.img"
local compat_option = "--ignore-minor-compat-version"
local function filehandler(_, chunk, eof)
if not unistd.access(tmpfile) and not file and chunk and #chunk > 0 then
file = io.open(tmpfile, "w")
end
if file and chunk then
file:write(chunk)
end
if file and eof then
file:close()
end
end
local function action_upgrade(http, renderer)
local fcntl = require 'posix.fcntl'
local stat = require 'posix.sys.stat'
local function fork_exec(argv)
local pid = unistd.fork()
if pid > 0 then
return
elseif pid == 0 then
-- change to root dir
unistd.chdir('/')
-- patch stdin, out, err to /dev/null
local null = fcntl.open('/dev/null', fcntl.O_RDWR)
if null then
unistd.dup2(null, unistd.STDIN_FILENO)
unistd.dup2(null, unistd.STDOUT_FILENO)
unistd.dup2(null, unistd.STDERR_FILENO)
if null > 2 then
unistd.close(null)
end
end
-- Sleep a little so the browser can fetch everything required to
-- display the reboot page, then reboot the device.
unistd.sleep(1)
-- replace with target command
unistd.exec(argv[0], argv)
end
end
local function image_supported(supported_tmpfile)
return (os.execute(string.format("exec /sbin/sysupgrade -T %s %q >/dev/null", compat_option, supported_tmpfile)) == 0)
end
local function storage_size()
local size = 0
if unistd.access("/proc/mtd") then
for l in io.lines("/proc/mtd") do
local s, n = l:match('^[^%s]+%s+([^%s]+)%s+[^%s]+%s+"([^%s]+)"')
if n == "firmware" then
size = tonumber(s, 16)
break
end
end
elseif unistd.access("/proc/partitions") then
for l in io.lines("/proc/partitions") do
local b, n = l:match('^%s*%d+%s+%d+%s+([^%s]+)%s+([^%s]+)')
if b and n and not n:match('[0-9]') then
size = tonumber(b) * 1024
break
end
end
end
return size
end
local function image_checksum(checksum_tmpfile)
return (util.exec(string.format("exec sha256sum %q", checksum_tmpfile)):match("^([^%s]+)"))
end
-- Determine state
local step = tonumber(http:getenv("REQUEST_METHOD") == "POST" and http:formvalue("step")) or 1
local has_image = unistd.access(tmpfile)
local has_support = has_image and image_supported(tmpfile)
-- Step 1: file upload, error on unsupported image format
if step == 1 or not has_support then
-- If there is an image but user has requested step 1
-- or type is not supported, then remove it.
if has_image then
unistd.unlink(tmpfile)
end
renderer.render_layout('admin/upgrade', {
bad_image = has_image and not has_support,
}, 'gluon-web-admin')
-- Step 2: present uploaded file, show checksum, confirmation
elseif step == 2 then
renderer.render_layout('admin/upgrade_confirm', {
checksum = image_checksum(tmpfile),
filesize = stat.stat(tmpfile).st_size,
flashsize = storage_size(),
keepconfig = (http:formvalue("keepcfg") == "1"),
}, 'gluon-web-admin')
elseif step == 3 then
local cmd = {[0] = '/sbin/sysupgrade', compat_option, tmpfile}
if http:formvalue('keepcfg') ~= '1' then
table.insert(cmd, 1, '-n')
end
fork_exec(cmd)
renderer.render_layout('admin/upgrade_reboot', nil, 'gluon-web-admin', {
hidenav = true,
})
end
end
local has_platform = unistd.access("/lib/upgrade/platform.sh")
if has_platform then
local upgrade = entry({"admin", "upgrade"}, call(action_upgrade), _("Upgrade firmware"), 90)
upgrade.filehandler = filehandler
end