autoupdater: convert spaces to tabs
This commit is contained in:
parent
463f872844
commit
ac55ad56b5
|
@ -8,126 +8,126 @@ module('autoupdater.util', package.seeall)
|
||||||
|
|
||||||
-- Executes a command in the background, without parsing the command through a shell (in contrast to os.execute)
|
-- Executes a command in the background, without parsing the command through a shell (in contrast to os.execute)
|
||||||
function exec(timeout, ...)
|
function exec(timeout, ...)
|
||||||
local pid, errno, error = nixio.fork()
|
local pid, errno, error = nixio.fork()
|
||||||
if pid == 0 then
|
if pid == 0 then
|
||||||
nixio.execp(...)
|
nixio.execp(...)
|
||||||
os.exit(127)
|
os.exit(127)
|
||||||
elseif pid > 0 then
|
elseif pid > 0 then
|
||||||
if timeout then
|
if timeout then
|
||||||
local starttime = os.time()
|
local starttime = os.time()
|
||||||
while true do
|
while true do
|
||||||
if os.difftime(os.time(), starttime) > timeout then
|
if os.difftime(os.time(), starttime) > timeout then
|
||||||
nixio.kill(pid, nixio.const.SIGTERM)
|
nixio.kill(pid, nixio.const.SIGTERM)
|
||||||
end
|
end
|
||||||
|
|
||||||
local wpid, status, code = nixio.waitpid(pid, 'nohang')
|
local wpid, status, code = nixio.waitpid(pid, 'nohang')
|
||||||
if wpid then
|
if wpid then
|
||||||
return wpid and status == 'exited' and code
|
return wpid and status == 'exited' and code
|
||||||
end
|
end
|
||||||
nixio.nanosleep(1)
|
nixio.nanosleep(1)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local wpid, status, code = nixio.waitpid(pid)
|
local wpid, status, code = nixio.waitpid(pid)
|
||||||
return wpid and status == 'exited' and code
|
return wpid and status == 'exited' and code
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return pid, errno, error
|
return pid, errno, error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Executes a command in the background, returning its PID and a pipe connected to the command's standard input
|
-- Executes a command in the background, returning its PID and a pipe connected to the command's standard input
|
||||||
function popen(write, ...)
|
function popen(write, ...)
|
||||||
local inr, inw = nixio.pipe()
|
local inr, inw = nixio.pipe()
|
||||||
local pid = nixio.fork()
|
local pid = nixio.fork()
|
||||||
|
|
||||||
if pid > 0 then
|
if pid > 0 then
|
||||||
if write then
|
if write then
|
||||||
inr:close()
|
inr:close()
|
||||||
return pid, inw
|
return pid, inw
|
||||||
else
|
else
|
||||||
inw:close()
|
inw:close()
|
||||||
return pid, inr
|
return pid, inr
|
||||||
end
|
end
|
||||||
elseif pid == 0 then
|
elseif pid == 0 then
|
||||||
if write then
|
if write then
|
||||||
nixio.dup(inr, nixio.stdin)
|
nixio.dup(inr, nixio.stdin)
|
||||||
else
|
else
|
||||||
nixio.dup(inw, nixio.stdout)
|
nixio.dup(inw, nixio.stdout)
|
||||||
end
|
end
|
||||||
|
|
||||||
inr:close()
|
inr:close()
|
||||||
inw:close()
|
inw:close()
|
||||||
|
|
||||||
nixio.execp(...)
|
nixio.execp(...)
|
||||||
os.exit(127)
|
os.exit(127)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Executes all executable files in a directory
|
-- Executes all executable files in a directory
|
||||||
function run_dir(dir)
|
function run_dir(dir)
|
||||||
local function is_ok(entry)
|
local function is_ok(entry)
|
||||||
if entry:sub(1, 1) == '.' then
|
if entry:sub(1, 1) == '.' then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local file = dir .. '/' .. entry
|
local file = dir .. '/' .. entry
|
||||||
if fs.stat(file, 'type') ~= 'reg' then
|
if fs.stat(file, 'type') ~= 'reg' then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if not fs.access(file, 'x') then
|
if not fs.access(file, 'x') then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local files = util.consume(fs.dir(dir))
|
local files = util.consume(fs.dir(dir))
|
||||||
if not files then
|
if not files then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
table.sort(files)
|
table.sort(files)
|
||||||
|
|
||||||
for _, entry in ipairs(files) do
|
for _, entry in ipairs(files) do
|
||||||
if is_ok(entry) then
|
if is_ok(entry) then
|
||||||
exec(nil, dir .. '/' .. entry)
|
exec(nil, dir .. '/' .. entry)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Seeds Lua's random generator from /dev/urandom
|
-- Seeds Lua's random generator from /dev/urandom
|
||||||
function randomseed()
|
function randomseed()
|
||||||
local f = io.open('/dev/urandom', 'r')
|
local f = io.open('/dev/urandom', 'r')
|
||||||
local b1, b2, b3, b4 = f:read(4):byte(1, 4)
|
local b1, b2, b3, b4 = f:read(4):byte(1, 4)
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
-- The and is necessary as Lua on OpenWrt doesn't like integers over 2^31-1
|
-- The and is necessary as Lua on OpenWrt doesn't like integers over 2^31-1
|
||||||
math.randomseed(nixio.bit.band(b1*0x1000000 + b2*0x10000 + b3*0x100 + b4, 0x7fffffff))
|
math.randomseed(nixio.bit.band(b1*0x1000000 + b2*0x10000 + b3*0x100 + b4, 0x7fffffff))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Takes a date and time in RFC3339 format and returns a Unix timestamp
|
-- Takes a date and time in RFC3339 format and returns a Unix timestamp
|
||||||
function parse_date(date)
|
function parse_date(date)
|
||||||
local year, month, day, hour, minute, second, tzs, tzh, tzm = date:match('^(%d%d%d%d)%-(%d%d)%-(%d%d) (%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$')
|
local year, month, day, hour, minute, second, tzs, tzh, tzm = date:match('^(%d%d%d%d)%-(%d%d)%-(%d%d) (%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$')
|
||||||
if not year then
|
if not year then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local a = math.floor((14 - month)/12)
|
local a = math.floor((14 - month)/12)
|
||||||
local y = year - a
|
local y = year - a
|
||||||
local m = month + 12*a - 3
|
local m = month + 12*a - 3
|
||||||
|
|
||||||
-- Based on a well-known formula for Julian dates
|
-- Based on a well-known formula for Julian dates
|
||||||
local days = day + math.floor((153*m + 2)/5) + 365*y + math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 719469
|
local days = day + math.floor((153*m + 2)/5) + 365*y + math.floor(y/4) - math.floor(y/100) + math.floor(y/400) - 719469
|
||||||
local time = hour*3600 + minute*60 + second
|
local time = hour*3600 + minute*60 + second
|
||||||
local tz = tzh*3600 + tzm*60
|
local tz = tzh*3600 + tzm*60
|
||||||
|
|
||||||
if tzs == '-' then
|
if tzs == '-' then
|
||||||
tz = -tz
|
tz = -tz
|
||||||
end
|
end
|
||||||
|
|
||||||
return days * 86400 + time - tz
|
return days * 86400 + time - tz
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,77 +3,77 @@ module 'autoupdater.version'
|
||||||
|
|
||||||
-- version comparison is based on dpkg code
|
-- version comparison is based on dpkg code
|
||||||
local function isdigit(s, i)
|
local function isdigit(s, i)
|
||||||
local c = s:sub(i, i)
|
local c = s:sub(i, i)
|
||||||
return c and c:match('^%d$')
|
return c and c:match('^%d$')
|
||||||
end
|
end
|
||||||
|
|
||||||
local function char_value(s, i)
|
local function char_value(s, i)
|
||||||
return s:byte(i, i) or 0
|
return s:byte(i, i) or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function char_order(s, i)
|
local function char_order(s, i)
|
||||||
local c = s:sub(i, i)
|
local c = s:sub(i, i)
|
||||||
|
|
||||||
if c == '' or c:match('^%d$') then
|
if c == '' or c:match('^%d$') then
|
||||||
return 0
|
return 0
|
||||||
elseif c:match('^%a$') then
|
elseif c:match('^%a$') then
|
||||||
return c:byte()
|
return c:byte()
|
||||||
elseif c == '~' then
|
elseif c == '~' then
|
||||||
return -1
|
return -1
|
||||||
else
|
else
|
||||||
return c:byte() + 256
|
return c:byte() + 256
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- returns true when a is a higher version number than b
|
-- returns true when a is a higher version number than b
|
||||||
function newer_than(a, b)
|
function newer_than(a, b)
|
||||||
local apos = 1
|
local apos = 1
|
||||||
local bpos = 1
|
local bpos = 1
|
||||||
|
|
||||||
while apos <= a:len() or bpos <= b:len() do
|
while apos <= a:len() or bpos <= b:len() do
|
||||||
local first_diff = 0
|
local first_diff = 0
|
||||||
|
|
||||||
while (apos <= a:len() and not isdigit(a, apos)) or (bpos <= b:len() and not isdigit(b, bpos)) do
|
while (apos <= a:len() and not isdigit(a, apos)) or (bpos <= b:len() and not isdigit(b, bpos)) do
|
||||||
local ac = char_order(a, apos)
|
local ac = char_order(a, apos)
|
||||||
local bc = char_order(b, bpos)
|
local bc = char_order(b, bpos)
|
||||||
|
|
||||||
if ac ~= bc then
|
if ac ~= bc then
|
||||||
return ac > bc
|
return ac > bc
|
||||||
end
|
end
|
||||||
|
|
||||||
apos = apos + 1
|
apos = apos + 1
|
||||||
bpos = bpos + 1
|
bpos = bpos + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
while a:sub(apos, apos) == '0' do
|
while a:sub(apos, apos) == '0' do
|
||||||
apos = apos + 1
|
apos = apos + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
while b:sub(bpos, bpos) == '0' do
|
while b:sub(bpos, bpos) == '0' do
|
||||||
bpos = bpos + 1
|
bpos = bpos + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
while isdigit(a, apos) and isdigit(b, bpos) do
|
while isdigit(a, apos) and isdigit(b, bpos) do
|
||||||
if first_diff == 0 then
|
if first_diff == 0 then
|
||||||
first_diff = char_value(a, apos) - char_value(b, bpos)
|
first_diff = char_value(a, apos) - char_value(b, bpos)
|
||||||
end
|
end
|
||||||
|
|
||||||
apos = apos + 1
|
apos = apos + 1
|
||||||
bpos = bpos + 1
|
bpos = bpos + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if isdigit(a, apos) then
|
if isdigit(a, apos) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if isdigit(b, bpos) then
|
if isdigit(b, bpos) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if first_diff ~= 0 then
|
if first_diff ~= 0 then
|
||||||
return first_diff > 0
|
return first_diff > 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,8 +11,8 @@ local autoupdater_version = require('autoupdater.version')
|
||||||
|
|
||||||
|
|
||||||
if not platform_info.get_image_name() then
|
if not platform_info.get_image_name() then
|
||||||
io.stderr:write("The autoupdater doesn't support this hardware model.\n")
|
io.stderr:write("The autoupdater doesn't support this hardware model.\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,30 +38,30 @@ local fallback = false
|
||||||
local mirrors = {}
|
local mirrors = {}
|
||||||
|
|
||||||
local function parse_args()
|
local function parse_args()
|
||||||
local i = 1
|
local i = 1
|
||||||
while arg[i] do
|
while arg[i] do
|
||||||
if arg[i] == '-f' then
|
if arg[i] == '-f' then
|
||||||
force = true
|
force = true
|
||||||
elseif arg[i] == '--fallback' then
|
elseif arg[i] == '--fallback' then
|
||||||
fallback = true
|
fallback = true
|
||||||
elseif arg[i] == '-b' then
|
elseif arg[i] == '-b' then
|
||||||
i = i+1
|
i = i+1
|
||||||
|
|
||||||
if not arg[i] then
|
if not arg[i] then
|
||||||
io.stderr:write("Error parsing command line: expected branch name\n")
|
io.stderr:write("Error parsing command line: expected branch name\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
branch_name = arg[i]
|
branch_name = arg[i]
|
||||||
elseif arg[i]:sub(0, 1) == '-' then
|
elseif arg[i]:sub(0, 1) == '-' then
|
||||||
io.stderr:write("Error parsing command line: unexpected argument '" .. arg[i] .. "'\n")
|
io.stderr:write("Error parsing command line: unexpected argument '" .. arg[i] .. "'\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
else
|
else
|
||||||
table.insert(mirrors, arg[i])
|
table.insert(mirrors, arg[i])
|
||||||
end
|
end
|
||||||
|
|
||||||
i = i+1
|
i = i+1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,274 +70,274 @@ parse_args()
|
||||||
|
|
||||||
local branch = uci:get_all('autoupdater', branch_name)
|
local branch = uci:get_all('autoupdater', branch_name)
|
||||||
if not branch then
|
if not branch then
|
||||||
io.stderr:write("Can't find configuration for branch '" .. branch_name .. "'\n")
|
io.stderr:write("Can't find configuration for branch '" .. branch_name .. "'\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if settings.enabled ~= '1' and not force then
|
if settings.enabled ~= '1' and not force then
|
||||||
io.stderr:write('autoupdater is disabled.\n')
|
io.stderr:write('autoupdater is disabled.\n')
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Verifies a file given as a list of lines with a list of signatures using ecdsaverify
|
-- Verifies a file given as a list of lines with a list of signatures using ecdsaverify
|
||||||
local function verify_lines(lines, sigs)
|
local function verify_lines(lines, sigs)
|
||||||
local command = {'ecdsaverify', '-n', tostring(branch.good_signatures)}
|
local command = {'ecdsaverify', '-n', tostring(branch.good_signatures)}
|
||||||
|
|
||||||
-- Build command line from sigs and branch.pubkey
|
-- Build command line from sigs and branch.pubkey
|
||||||
for _, sig in ipairs(sigs) do
|
for _, sig in ipairs(sigs) do
|
||||||
if sig:match('^' .. string.rep('%x', 128) .. '$') then
|
if sig:match('^' .. string.rep('%x', 128) .. '$') then
|
||||||
table.insert(command, '-s')
|
table.insert(command, '-s')
|
||||||
table.insert(command, sig)
|
table.insert(command, sig)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, key in ipairs(branch.pubkey) do
|
for _, key in ipairs(branch.pubkey) do
|
||||||
if key:match('^' .. string.rep('%x', 64) .. '$') then
|
if key:match('^' .. string.rep('%x', 64) .. '$') then
|
||||||
table.insert(command, '-p')
|
table.insert(command, '-p')
|
||||||
table.insert(command, key)
|
table.insert(command, key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Call ecdsautils
|
-- Call ecdsautils
|
||||||
local pid, f = autoupdater_util.popen(true, unpack(command))
|
local pid, f = autoupdater_util.popen(true, unpack(command))
|
||||||
|
|
||||||
for _, line in ipairs(lines) do
|
for _, line in ipairs(lines) do
|
||||||
f:write(line)
|
f:write(line)
|
||||||
f:write('\n')
|
f:write('\n')
|
||||||
end
|
end
|
||||||
|
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
|
|
||||||
local wpid, status, code = nixio.waitpid(pid)
|
local wpid, status, code = nixio.waitpid(pid)
|
||||||
return wpid and status == 'exited' and code == 0
|
return wpid and status == 'exited' and code == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Downloads, parses and verifies the update manifest from a mirror
|
-- Downloads, parses and verifies the update manifest from a mirror
|
||||||
-- Returns a table with the fields version, checksum and filename if everything is ok, nil otherwise
|
-- Returns a table with the fields version, checksum and filename if everything is ok, nil otherwise
|
||||||
local function read_manifest(mirror)
|
local function read_manifest(mirror)
|
||||||
local sep = false
|
local sep = false
|
||||||
|
|
||||||
local lines = {}
|
local lines = {}
|
||||||
local sigs = {}
|
local sigs = {}
|
||||||
|
|
||||||
local branch_ok = false
|
local branch_ok = false
|
||||||
|
|
||||||
local ret = {}
|
local ret = {}
|
||||||
|
|
||||||
-- Remove potential trailing slash
|
-- Remove potential trailing slash
|
||||||
mirror = mirror:gsub('/$', '')
|
mirror = mirror:gsub('/$', '')
|
||||||
|
|
||||||
|
|
||||||
local starttime = os.time()
|
local starttime = os.time()
|
||||||
local pid, manifest_loader = autoupdater_util.popen(false, 'wget', '-T', '120', '-O-', string.format('%s/%s.manifest', mirror, branch.name))
|
local pid, manifest_loader = autoupdater_util.popen(false, 'wget', '-T', '120', '-O-', string.format('%s/%s.manifest', mirror, branch.name))
|
||||||
|
|
||||||
local data = ''
|
local data = ''
|
||||||
|
|
||||||
-- Read all lines from the manifest
|
-- Read all lines from the manifest
|
||||||
-- The upper part is saved to lines, the lower part to sigs
|
-- The upper part is saved to lines, the lower part to sigs
|
||||||
while true do
|
while true do
|
||||||
-- If the manifest download takes more than 5 minutes, we don't really
|
-- If the manifest download takes more than 5 minutes, we don't really
|
||||||
-- have a chance to download a whole image
|
-- have a chance to download a whole image
|
||||||
local timeout = starttime+300 - os.time()
|
local timeout = starttime+300 - os.time()
|
||||||
if timeout < 0 or not nixio.poll({{fd = manifest_loader, events = nixio.poll_flags('in')}}, timeout * 1000) then
|
if timeout < 0 or not nixio.poll({{fd = manifest_loader, events = nixio.poll_flags('in')}}, timeout * 1000) then
|
||||||
io.stderr:write("Timeout while reading manifest.\n")
|
io.stderr:write("Timeout while reading manifest.\n")
|
||||||
nixio.kill(pid, nixio.const.SIGTERM)
|
nixio.kill(pid, nixio.const.SIGTERM)
|
||||||
manifest_loader:close()
|
manifest_loader:close()
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local r = manifest_loader:read(1024)
|
local r = manifest_loader:read(1024)
|
||||||
if not r or r == '' then
|
if not r or r == '' then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
data = data .. r
|
data = data .. r
|
||||||
|
|
||||||
while data:match('\n') do
|
while data:match('\n') do
|
||||||
local line, rest = data:match('^([^\n]*)\n(.*)$')
|
local line, rest = data:match('^([^\n]*)\n(.*)$')
|
||||||
data = rest
|
data = rest
|
||||||
|
|
||||||
if not sep then
|
if not sep then
|
||||||
if line == '---' then
|
if line == '---' then
|
||||||
sep = true
|
sep = true
|
||||||
else
|
else
|
||||||
table.insert(lines, line)
|
table.insert(lines, line)
|
||||||
|
|
||||||
if line == ('BRANCH=' .. branch.name) then
|
if line == ('BRANCH=' .. branch.name) then
|
||||||
branch_ok = true
|
branch_ok = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local date = line:match('^DATE=(.+)$')
|
local date = line:match('^DATE=(.+)$')
|
||||||
local priority = line:match('^PRIORITY=([%d%.]+)$')
|
local priority = line:match('^PRIORITY=([%d%.]+)$')
|
||||||
local model, version, checksum, filename = line:match('^([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)$')
|
local model, version, checksum, filename = line:match('^([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)$')
|
||||||
|
|
||||||
if date then
|
if date then
|
||||||
ret.date = autoupdater_util.parse_date(date)
|
ret.date = autoupdater_util.parse_date(date)
|
||||||
elseif priority then
|
elseif priority then
|
||||||
ret.priority = tonumber(priority)
|
ret.priority = tonumber(priority)
|
||||||
elseif model == platform_info.get_image_name() then
|
elseif model == platform_info.get_image_name() then
|
||||||
ret.version = version
|
ret.version = version
|
||||||
ret.checksum = checksum
|
ret.checksum = checksum
|
||||||
ret.filename = filename
|
ret.filename = filename
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert(sigs, line)
|
table.insert(sigs, line)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
manifest_loader:close()
|
manifest_loader:close()
|
||||||
|
|
||||||
-- Do some very basic checks before checking the signatures
|
-- Do some very basic checks before checking the signatures
|
||||||
-- (as the signature verification is computationally expensive)
|
-- (as the signature verification is computationally expensive)
|
||||||
if not sep then
|
if not sep then
|
||||||
io.stderr:write('There seems to have gone something wrong downloading the manifest from ' .. mirror .. '\n')
|
io.stderr:write('There seems to have gone something wrong downloading the manifest from ' .. mirror .. '\n')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if not ret.date or not ret.priority then
|
if not ret.date or not ret.priority then
|
||||||
io.stderr:write('The manifest downloaded from ' .. mirror .. ' is invalid (DATE or PRIORITY missing)\n')
|
io.stderr:write('The manifest downloaded from ' .. mirror .. ' is invalid (DATE or PRIORITY missing)\n')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if not branch_ok then
|
if not branch_ok then
|
||||||
io.stderr:write('Wrong branch. We are on ', branch.name, '.\n')
|
io.stderr:write('Wrong branch. We are on ', branch.name, '.\n')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if not ret.version then
|
if not ret.version then
|
||||||
io.stderr:write('No matching firmware found (model ' .. platform_info.get_image_name() .. ')\n')
|
io.stderr:write('No matching firmware found (model ' .. platform_info.get_image_name() .. ')\n')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if not verify_lines(lines, sigs) then
|
if not verify_lines(lines, sigs) then
|
||||||
io.stderr:write('Not enough valid signatures!\n')
|
io.stderr:write('Not enough valid signatures!\n')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Downloads the firmware image from a mirror to a given output file
|
-- Downloads the firmware image from a mirror to a given output file
|
||||||
local function fetch_firmware(mirror, filename, output)
|
local function fetch_firmware(mirror, filename, output)
|
||||||
-- Let's give the image download 30 minutes, hopefully more than enough
|
-- Let's give the image download 30 minutes, hopefully more than enough
|
||||||
if autoupdater_util.exec(1800, 'wget', '-T', '120', '-O', output, mirror .. '/' .. filename) ~= 0 then
|
if autoupdater_util.exec(1800, 'wget', '-T', '120', '-O', output, mirror .. '/' .. filename) ~= 0 then
|
||||||
io.stderr:write('Error downloading the image from ' .. mirror .. '\n')
|
io.stderr:write('Error downloading the image from ' .. mirror .. '\n')
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Returns the computed update probability
|
-- Returns the computed update probability
|
||||||
local function get_probability(date, priority)
|
local function get_probability(date, priority)
|
||||||
local seconds = priority * 86400
|
local seconds = priority * 86400
|
||||||
local diff = os.difftime(os.time(), date)
|
local diff = os.difftime(os.time(), date)
|
||||||
|
|
||||||
if diff < 0 then
|
if diff < 0 then
|
||||||
-- When the difference is negative, there are two possibilities: The manifest contains a wrong date, or our own clock is wrong.
|
-- When the difference is negative, there are two possibilities: The manifest contains a wrong date, or our own clock is wrong.
|
||||||
-- As there isn't anything useful to do for an incorrect manifest, we'll assume the latter case and update anyways as we
|
-- As there isn't anything useful to do for an incorrect manifest, we'll assume the latter case and update anyways as we
|
||||||
-- can't do anything better
|
-- can't do anything better
|
||||||
io.stderr:write('Warning: clock seems to be incorrect.\n')
|
io.stderr:write('Warning: clock seems to be incorrect.\n')
|
||||||
|
|
||||||
if tonumber(fs.readfile('/proc/uptime'):match('^([^ ]+) ')) < 600 then
|
if tonumber(fs.readfile('/proc/uptime'):match('^([^ ]+) ')) < 600 then
|
||||||
-- If the uptime is very low, it's possible we just didn't get the time over NTP yet, so we'll just wait until the next time the updater runs
|
-- If the uptime is very low, it's possible we just didn't get the time over NTP yet, so we'll just wait until the next time the updater runs
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
-- Will give 1 when priority == 0, and lower probabilities the higher the priority value is
|
-- Will give 1 when priority == 0, and lower probabilities the higher the priority value is
|
||||||
-- (similar to the old static probability system)
|
-- (similar to the old static probability system)
|
||||||
return 0.75^priority
|
return 0.75^priority
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif fallback then
|
elseif fallback then
|
||||||
if diff >= seconds + 86400 then
|
if diff >= seconds + 86400 then
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif diff >= seconds then
|
elseif diff >= seconds then
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
else
|
else
|
||||||
local x = diff/seconds
|
local x = diff/seconds
|
||||||
-- This is the most simple polynomial with value 0 at 0, 1 at 1, and whose first derivative is 0 at both 0 and 1
|
-- This is the most simple polynomial with value 0 at 0, 1 at 1, and whose first derivative is 0 at both 0 and 1
|
||||||
-- (we all love continuously differentiable functions, right?)
|
-- (we all love continuously differentiable functions, right?)
|
||||||
return (-2)*x^3 + 3*x^2
|
return (-2)*x^3 + 3*x^2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Tries to perform an update from a given mirror
|
-- Tries to perform an update from a given mirror
|
||||||
local function autoupdate(mirror)
|
local function autoupdate(mirror)
|
||||||
local download_d_dir = '/usr/lib/autoupdater/download.d'
|
local download_d_dir = '/usr/lib/autoupdater/download.d'
|
||||||
local abort_d_dir = '/usr/lib/autoupdater/abort.d'
|
local abort_d_dir = '/usr/lib/autoupdater/abort.d'
|
||||||
local upgrade_d_dir = '/usr/lib/autoupdater/upgrade.d'
|
local upgrade_d_dir = '/usr/lib/autoupdater/upgrade.d'
|
||||||
|
|
||||||
|
|
||||||
local manifest = read_manifest(mirror)
|
local manifest = read_manifest(mirror)
|
||||||
if not manifest then
|
if not manifest then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if not autoupdater_version.newer_than(manifest.version, old_version) then
|
if not autoupdater_version.newer_than(manifest.version, old_version) then
|
||||||
io.stderr:write('No new firmware available.\n')
|
io.stderr:write('No new firmware available.\n')
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
io.stderr:write('New version available.\n')
|
io.stderr:write('New version available.\n')
|
||||||
|
|
||||||
|
|
||||||
if not force and math.random() >= get_probability(manifest.date, manifest.priority) then
|
if not force and math.random() >= get_probability(manifest.date, manifest.priority) then
|
||||||
io.stderr:write('No autoupdate this time. Use -f to override.\n')
|
io.stderr:write('No autoupdate this time. Use -f to override.\n')
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
autoupdater_util.run_dir(download_d_dir)
|
autoupdater_util.run_dir(download_d_dir)
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
|
|
||||||
local image = os.tmpname()
|
local image = os.tmpname()
|
||||||
if not fetch_firmware(mirror, manifest.filename, image) then
|
if not fetch_firmware(mirror, manifest.filename, image) then
|
||||||
autoupdater_util.run_dir(abort_d_dir)
|
autoupdater_util.run_dir(abort_d_dir)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local popen = io.popen(string.format("exec sha512sum '%s'", image))
|
local popen = io.popen(string.format("exec sha512sum '%s'", image))
|
||||||
local checksum = popen:read('*l'):match('^%x+')
|
local checksum = popen:read('*l'):match('^%x+')
|
||||||
popen:close()
|
popen:close()
|
||||||
if checksum ~= manifest.checksum then
|
if checksum ~= manifest.checksum then
|
||||||
io.stderr:write('Invalid image checksum!\n')
|
io.stderr:write('Invalid image checksum!\n')
|
||||||
os.remove(image)
|
os.remove(image)
|
||||||
autoupdater_util.run_dir(abort_d_dir)
|
autoupdater_util.run_dir(abort_d_dir)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
autoupdater_util.run_dir(upgrade_d_dir)
|
autoupdater_util.run_dir(upgrade_d_dir)
|
||||||
|
|
||||||
io.stderr:write('Upgrading firmware...\n')
|
io.stderr:write('Upgrading firmware...\n')
|
||||||
local null = nixio.open('/dev/null', 'w+')
|
local null = nixio.open('/dev/null', 'w+')
|
||||||
if null then
|
if null then
|
||||||
nixio.dup(null, nixio.stdin)
|
nixio.dup(null, nixio.stdin)
|
||||||
nixio.dup(null, nixio.stderr)
|
nixio.dup(null, nixio.stderr)
|
||||||
if null:fileno() > 2 then
|
if null:fileno() > 2 then
|
||||||
null:close()
|
null:close()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
nixio.exec('/sbin/sysupgrade', image)
|
nixio.exec('/sbin/sysupgrade', image)
|
||||||
|
|
||||||
-- This should never be reached as nixio.exec replaces the autoupdater process unless /sbin/sysupgrade can't be executed
|
-- This should never be reached as nixio.exec replaces the autoupdater process unless /sbin/sysupgrade can't be executed
|
||||||
-- We output the error message through stdout as stderr isn't available anymore
|
-- We output the error message through stdout as stderr isn't available anymore
|
||||||
io.write('Failed to call sysupgrade?\n')
|
io.write('Failed to call sysupgrade?\n')
|
||||||
os.remove(image)
|
os.remove(image)
|
||||||
autoupdater_util.run_dir(abort_d_dir)
|
autoupdater_util.run_dir(abort_d_dir)
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,24 +345,24 @@ local lockfile = '/var/lock/autoupdater.lock'
|
||||||
local lockfd = nixio.open(lockfile, 'w', 'rw-------')
|
local lockfd = nixio.open(lockfile, 'w', 'rw-------')
|
||||||
|
|
||||||
if not lockfd:lock('tlock') then
|
if not lockfd:lock('tlock') then
|
||||||
io.stderr:write(string.format(
|
io.stderr:write(string.format(
|
||||||
"Unable to lock file %s. Make sure there is no other instance of the autoupdater running.\n",
|
"Unable to lock file %s. Make sure there is no other instance of the autoupdater running.\n",
|
||||||
lockfile, err
|
lockfile, err
|
||||||
))
|
))
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if #mirrors == 0 then
|
if #mirrors == 0 then
|
||||||
while #branch.mirror > 0 do
|
while #branch.mirror > 0 do
|
||||||
table.insert(mirrors, table.remove(branch.mirror, math.random(#branch.mirror)))
|
table.insert(mirrors, table.remove(branch.mirror, math.random(#branch.mirror)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for k, mirror in ipairs(mirrors) do
|
for k, mirror in ipairs(mirrors) do
|
||||||
if autoupdate(mirror) then
|
if autoupdate(mirror) then
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
io.stderr:write('No usable mirror found.\n')
|
io.stderr:write('No usable mirror found.\n')
|
||||||
|
|
Loading…
Reference in New Issue