From b7ce1a2002f254544deaed8e4d71ceb1ad731c75 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 10 Jan 2016 13:32:35 +0100 Subject: [PATCH] autoupdater: add download.d and abort.d directories All executables in download.d are executed before after the update manifest has been verified, but before the image is downloaded. This can be used to stop non-essential services to free RAM. abort.d is run when the download has failed and should revert the actions of download.d. --- .../files/usr/lib/autoupdater/abort.d/README | 6 +++ .../lib/autoupdater/download.d/95drop_caches | 4 ++ .../usr/lib/autoupdater/download.d/README | 2 + .../files/usr/lib/lua/autoupdater/util.lua | 39 +++++++++++++++++-- admin/autoupdater/files/usr/sbin/autoupdater | 11 ++++-- 5 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 admin/autoupdater/files/usr/lib/autoupdater/abort.d/README create mode 100755 admin/autoupdater/files/usr/lib/autoupdater/download.d/95drop_caches create mode 100644 admin/autoupdater/files/usr/lib/autoupdater/download.d/README diff --git a/admin/autoupdater/files/usr/lib/autoupdater/abort.d/README b/admin/autoupdater/files/usr/lib/autoupdater/abort.d/README new file mode 100644 index 0000000..014518a --- /dev/null +++ b/admin/autoupdater/files/usr/lib/autoupdater/abort.d/README @@ -0,0 +1,6 @@ +Executable files in abort.d will be executed if downloading the upgrade +image has failed and should revert the actions from download.d. + +We can't really do anything when the download has succeeded, but the +flashing has failed, as the autoupdater process will have been replaced by +sysupgrade by then. diff --git a/admin/autoupdater/files/usr/lib/autoupdater/download.d/95drop_caches b/admin/autoupdater/files/usr/lib/autoupdater/download.d/95drop_caches new file mode 100755 index 0000000..814159f --- /dev/null +++ b/admin/autoupdater/files/usr/lib/autoupdater/download.d/95drop_caches @@ -0,0 +1,4 @@ +#!/bin/sh + +sync +sysctl -w vm.drop_caches=3 diff --git a/admin/autoupdater/files/usr/lib/autoupdater/download.d/README b/admin/autoupdater/files/usr/lib/autoupdater/download.d/README new file mode 100644 index 0000000..c1c53e5 --- /dev/null +++ b/admin/autoupdater/files/usr/lib/autoupdater/download.d/README @@ -0,0 +1,2 @@ +Executable files in download.d will be executed after the update manifest +has been verified, but before the actual image is downloaded. diff --git a/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua b/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua index 08c03db..d5dd67e 100644 --- a/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua +++ b/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua @@ -1,9 +1,9 @@ -local io = io -local math = math local nixio = require 'nixio' +local fs = require 'nixio.fs' +local util = require 'nixio.util' -module 'autoupdater.util' +module('autoupdater.util', package.seeall) -- Executes a command in the background, without parsing the command through a shell (in contrast to os.execute) @@ -42,6 +42,39 @@ function popen(...) end +-- Executes all executable files in a directory +function run_dir(dir) + local function is_ok(entry) + if entry:sub(1, 1) == '.' then + return false + end + + local file = dir .. '/' .. entry + if fs.stat(file, 'type') ~= 'reg' then + return false + end + if not fs.access(file, 'x') then + return false + end + + return true + end + + local files = util.consume(fs.dir(dir)) + if not files then + return + end + + table.sort(files) + + for _, entry in ipairs(files) do + if is_ok(entry) then + exec(dir .. '/' .. entry) + end + end +end + + -- Seeds Lua's random generator from /dev/urandom function randomseed() local f = io.open('/dev/urandom', 'r') diff --git a/admin/autoupdater/files/usr/sbin/autoupdater b/admin/autoupdater/files/usr/sbin/autoupdater index 73510b1..681d35c 100755 --- a/admin/autoupdater/files/usr/sbin/autoupdater +++ b/admin/autoupdater/files/usr/sbin/autoupdater @@ -241,6 +241,10 @@ end -- Tries to perform an update from a given mirror local function autoupdate(mirror) + local download_d_dir = '/usr/lib/autoupdater/download.d' + local abort_d_dir = '/usr/lib/autoupdater/abort.d' + + local manifest = read_manifest(mirror) if not manifest then return false @@ -259,13 +263,12 @@ local function autoupdate(mirror) return true end - - autoupdater_util.exec('sync') - autoupdater_util.exec('sysctl', '-w', 'vm.drop_caches=3') + autoupdater_util.run_dir(download_d_dir) collectgarbage() local image = os.tmpname() if not fetch_firmware(mirror, manifest.filename, image) then + autoupdater_util.run_dir(abort_d_dir) return false end @@ -275,6 +278,7 @@ local function autoupdate(mirror) if checksum ~= manifest.checksum then io.stderr:write('Invalid image checksum!\n') os.remove(image) + autoupdater_util.run_dir(abort_d_dir) return false end @@ -294,6 +298,7 @@ local function autoupdate(mirror) -- We output the error message through stdout as stderr isn't available anymore io.write('Failed to call sysupgrade?\n') os.remove(image) + autoupdater_util.run_dir(abort_d_dir) os.exit(1) end