From 90380414f10842238b7ebc21c34dbaf986659320 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 8 Sep 2016 03:09:30 +0200 Subject: [PATCH] autoupdater: add timeouts to wget calls The -T parameter only seems to limit the maximum time between received packets, but not the overall run time. This adds simple timeouts to the wget calls (5 minutes for the manifest, 30 minutes for the image). The implementation is very simple, only checking the manifest timeout each time a line was received, and the image timeout once a second. A more elegent fix seems like overkill, as the Lua autoupdater will be replaced with a new implementation after Gluon 2016.2 anyways. --- .../files/usr/lib/lua/autoupdater/util.lua | 23 +++++++++++++++---- admin/autoupdater/files/usr/sbin/autoupdater | 19 ++++++++++++--- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua b/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua index d5dd67e..b1d8c58 100644 --- a/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua +++ b/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua @@ -7,14 +7,29 @@ module('autoupdater.util', package.seeall) -- Executes a command in the background, without parsing the command through a shell (in contrast to os.execute) -function exec(...) +function exec(timeout, ...) local pid, errno, error = nixio.fork() if pid == 0 then nixio.execp(...) os.exit(127) elseif pid > 0 then - local wpid, status, code = nixio.waitpid(pid) - return wpid and status == 'exited' and code + if timeout then + local starttime = os.time() + while true do + if os.difftime(os.time(), starttime) > timeout then + nixio.kill(pid, nixio.const.SIGTERM) + end + + local wpid, status, code = nixio.waitpid(pid, 'nohang') + if wpid then + return wpid and status == 'exited' and code + end + nixio.nanosleep(1) + end + else + local wpid, status, code = nixio.waitpid(pid) + return wpid and status == 'exited' and code + end else return pid, errno, error end @@ -69,7 +84,7 @@ function run_dir(dir) for _, entry in ipairs(files) do if is_ok(entry) then - exec(dir .. '/' .. entry) + exec(nil, dir .. '/' .. entry) end end end diff --git a/admin/autoupdater/files/usr/sbin/autoupdater b/admin/autoupdater/files/usr/sbin/autoupdater index bb54ee5..1b9112e 100755 --- a/admin/autoupdater/files/usr/sbin/autoupdater +++ b/admin/autoupdater/files/usr/sbin/autoupdater @@ -129,9 +129,21 @@ local function read_manifest(mirror) -- Remove potential trailing slash mirror = mirror:gsub('/$', '') + + local starttime = os.time() + local manifest_loader = io.popen(string.format("exec wget -T 120 -O- '%s/%s.manifest'", mirror, branch.name), 'r') + -- Read all lines from the manifest - -- The upper part is saves to lines, the lower part to sigs - for line in io.popen(string.format("exec wget -T 120 -O- '%s/%s.manifest'", mirror, branch.name), 'r'):lines() do + -- The upper part is saved to lines, the lower part to sigs + for line in manifest_loader:lines() do + -- If the manifest download takes more than 5 minutes, we don't really + -- have a chance to download a whole image + if os.difftime(os.time(), starttime) > 300 then + io.stderr:write("Timeout while reading manifest.\n") + manifest_loader:close() + return nil + end + if not sep then if line == '---' then sep = true @@ -194,7 +206,8 @@ end -- Downloads the firmware image from a mirror to a given output file local function fetch_firmware(mirror, filename, output) - if autoupdater_util.exec('wget', '-T', '120', '-O', output, mirror .. '/' .. filename) ~= 0 then + -- 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 io.stderr:write('Error downloading the image from ' .. mirror .. '\n') return false end