diff --git a/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua b/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua index 77f41b3..b6075ea 100644 --- a/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua +++ b/admin/autoupdater/files/usr/lib/lua/autoupdater/util.lua @@ -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) function exec(timeout, ...) - local pid, errno, error = nixio.fork() - if pid == 0 then - nixio.execp(...) - os.exit(127) - elseif pid > 0 then - 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 pid, errno, error = nixio.fork() + if pid == 0 then + nixio.execp(...) + os.exit(127) + elseif pid > 0 then + 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 + 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 end -- Executes a command in the background, returning its PID and a pipe connected to the command's standard input function popen(write, ...) - local inr, inw = nixio.pipe() - local pid = nixio.fork() + local inr, inw = nixio.pipe() + local pid = nixio.fork() - if pid > 0 then - if write then - inr:close() - return pid, inw - else - inw:close() - return pid, inr - end - elseif pid == 0 then - if write then - nixio.dup(inr, nixio.stdin) - else - nixio.dup(inw, nixio.stdout) - end + if pid > 0 then + if write then + inr:close() + return pid, inw + else + inw:close() + return pid, inr + end + elseif pid == 0 then + if write then + nixio.dup(inr, nixio.stdin) + else + nixio.dup(inw, nixio.stdout) + end - inr:close() - inw:close() + inr:close() + inw:close() - nixio.execp(...) - os.exit(127) - end + nixio.execp(...) + os.exit(127) + end 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 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 + 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 + return true + end - local files = util.consume(fs.dir(dir)) - if not files then - return - end + local files = util.consume(fs.dir(dir)) + if not files then + return + end - table.sort(files) + table.sort(files) - for _, entry in ipairs(files) do - if is_ok(entry) then - exec(nil, dir .. '/' .. entry) - end - end + for _, entry in ipairs(files) do + if is_ok(entry) then + exec(nil, dir .. '/' .. entry) + end + end end -- Seeds Lua's random generator from /dev/urandom function randomseed() - local f = io.open('/dev/urandom', 'r') - local b1, b2, b3, b4 = f:read(4):byte(1, 4) - f:close() + local f = io.open('/dev/urandom', 'r') + local b1, b2, b3, b4 = f:read(4):byte(1, 4) + f:close() - -- 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)) + -- 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)) end -- Takes a date and time in RFC3339 format and returns a Unix timestamp 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)$') - if not year then - return nil - end + 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 + return nil + end - local a = math.floor((14 - month)/12) - local y = year - a - local m = month + 12*a - 3 + local a = math.floor((14 - month)/12) + local y = year - a + local m = month + 12*a - 3 - -- 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 time = hour*3600 + minute*60 + second - local tz = tzh*3600 + tzm*60 + -- 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 time = hour*3600 + minute*60 + second + local tz = tzh*3600 + tzm*60 - if tzs == '-' then - tz = -tz - end + if tzs == '-' then + tz = -tz + end - return days * 86400 + time - tz + return days * 86400 + time - tz end diff --git a/admin/autoupdater/files/usr/lib/lua/autoupdater/version.lua b/admin/autoupdater/files/usr/lib/lua/autoupdater/version.lua index fecfe0c..9c951c5 100644 --- a/admin/autoupdater/files/usr/lib/lua/autoupdater/version.lua +++ b/admin/autoupdater/files/usr/lib/lua/autoupdater/version.lua @@ -3,77 +3,77 @@ module 'autoupdater.version' -- version comparison is based on dpkg code local function isdigit(s, i) - local c = s:sub(i, i) - return c and c:match('^%d$') + local c = s:sub(i, i) + return c and c:match('^%d$') end local function char_value(s, i) - return s:byte(i, i) or 0 + return s:byte(i, i) or 0 end 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 - return 0 - elseif c:match('^%a$') then - return c:byte() - elseif c == '~' then - return -1 - else - return c:byte() + 256 - end + if c == '' or c:match('^%d$') then + return 0 + elseif c:match('^%a$') then + return c:byte() + elseif c == '~' then + return -1 + else + return c:byte() + 256 + end end -- returns true when a is a higher version number than b function newer_than(a, b) - local apos = 1 - local bpos = 1 + local apos = 1 + local bpos = 1 - while apos <= a:len() or bpos <= b:len() do - local first_diff = 0 + while apos <= a:len() or bpos <= b:len() do + local first_diff = 0 - 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 bc = char_order(b, bpos) + 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 bc = char_order(b, bpos) - if ac ~= bc then + if ac ~= bc then return ac > bc - end + end - apos = apos + 1 - bpos = bpos + 1 - end + apos = apos + 1 + bpos = bpos + 1 + end - while a:sub(apos, apos) == '0' do - apos = apos + 1 - end + while a:sub(apos, apos) == '0' do + apos = apos + 1 + end - while b:sub(bpos, bpos) == '0' do - bpos = bpos + 1 - end + while b:sub(bpos, bpos) == '0' do + bpos = bpos + 1 + end - while isdigit(a, apos) and isdigit(b, bpos) do - if first_diff == 0 then + while isdigit(a, apos) and isdigit(b, bpos) do + if first_diff == 0 then first_diff = char_value(a, apos) - char_value(b, bpos) - end + end - apos = apos + 1 - bpos = bpos + 1 - end + apos = apos + 1 + bpos = bpos + 1 + end - if isdigit(a, apos) then - return true - end + if isdigit(a, apos) then + return true + end - if isdigit(b, bpos) then - return false - end + if isdigit(b, bpos) then + return false + end - if first_diff ~= 0 then - return first_diff > 0 - end - end + if first_diff ~= 0 then + return first_diff > 0 + end + end - return false + return false end diff --git a/admin/autoupdater/files/usr/sbin/autoupdater b/admin/autoupdater/files/usr/sbin/autoupdater index 2102cff..a0fe499 100755 --- a/admin/autoupdater/files/usr/sbin/autoupdater +++ b/admin/autoupdater/files/usr/sbin/autoupdater @@ -11,8 +11,8 @@ local autoupdater_version = require('autoupdater.version') if not platform_info.get_image_name() then - io.stderr:write("The autoupdater doesn't support this hardware model.\n") - os.exit(1) + io.stderr:write("The autoupdater doesn't support this hardware model.\n") + os.exit(1) end @@ -38,30 +38,30 @@ local fallback = false local mirrors = {} local function parse_args() - local i = 1 - while arg[i] do - if arg[i] == '-f' then - force = true - elseif arg[i] == '--fallback' then - fallback = true - elseif arg[i] == '-b' then - i = i+1 + local i = 1 + while arg[i] do + if arg[i] == '-f' then + force = true + elseif arg[i] == '--fallback' then + fallback = true + elseif arg[i] == '-b' then + i = i+1 - if not arg[i] then - io.stderr:write("Error parsing command line: expected branch name\n") - os.exit(1) - end + if not arg[i] then + io.stderr:write("Error parsing command line: expected branch name\n") + os.exit(1) + end - branch_name = arg[i] - elseif arg[i]:sub(0, 1) == '-' then - io.stderr:write("Error parsing command line: unexpected argument '" .. arg[i] .. "'\n") - os.exit(1) - else - table.insert(mirrors, arg[i]) - end + branch_name = arg[i] + elseif arg[i]:sub(0, 1) == '-' then + io.stderr:write("Error parsing command line: unexpected argument '" .. arg[i] .. "'\n") + os.exit(1) + else + table.insert(mirrors, arg[i]) + end - i = i+1 - end + i = i+1 + end end @@ -70,274 +70,274 @@ parse_args() local branch = uci:get_all('autoupdater', branch_name) if not branch then - io.stderr:write("Can't find configuration for branch '" .. branch_name .. "'\n") - os.exit(1) + io.stderr:write("Can't find configuration for branch '" .. branch_name .. "'\n") + os.exit(1) end if settings.enabled ~= '1' and not force then - io.stderr:write('autoupdater is disabled.\n') - os.exit(0) + io.stderr:write('autoupdater is disabled.\n') + os.exit(0) end -- Verifies a file given as a list of lines with a list of signatures using ecdsaverify 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 - for _, sig in ipairs(sigs) do - if sig:match('^' .. string.rep('%x', 128) .. '$') then - table.insert(command, '-s') - table.insert(command, sig) - end - end + -- Build command line from sigs and branch.pubkey + for _, sig in ipairs(sigs) do + if sig:match('^' .. string.rep('%x', 128) .. '$') then + table.insert(command, '-s') + table.insert(command, sig) + end + end - for _, key in ipairs(branch.pubkey) do - if key:match('^' .. string.rep('%x', 64) .. '$') then - table.insert(command, '-p') - table.insert(command, key) - end - end + for _, key in ipairs(branch.pubkey) do + if key:match('^' .. string.rep('%x', 64) .. '$') then + table.insert(command, '-p') + table.insert(command, key) + end + end - -- Call ecdsautils - local pid, f = autoupdater_util.popen(true, unpack(command)) + -- Call ecdsautils + local pid, f = autoupdater_util.popen(true, unpack(command)) - for _, line in ipairs(lines) do - f:write(line) - f:write('\n') - end + for _, line in ipairs(lines) do + f:write(line) + f:write('\n') + end - f:close() + f:close() - local wpid, status, code = nixio.waitpid(pid) - return wpid and status == 'exited' and code == 0 + local wpid, status, code = nixio.waitpid(pid) + return wpid and status == 'exited' and code == 0 end -- 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 local function read_manifest(mirror) - local sep = false + local sep = false - local lines = {} - local sigs = {} + local lines = {} + local sigs = {} - local branch_ok = false + local branch_ok = false - local ret = {} + local ret = {} - -- Remove potential trailing slash - mirror = mirror:gsub('/$', '') + -- Remove potential trailing slash + mirror = mirror:gsub('/$', '') - 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 starttime = os.time() + 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 - -- The upper part is saved to lines, the lower part to sigs - while true do - -- If the manifest download takes more than 5 minutes, we don't really - -- have a chance to download a whole image - local timeout = starttime+300 - os.time() - 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") - nixio.kill(pid, nixio.const.SIGTERM) - manifest_loader:close() - return nil - end + -- Read all lines from the manifest + -- The upper part is saved to lines, the lower part to sigs + while true do + -- If the manifest download takes more than 5 minutes, we don't really + -- have a chance to download a whole image + local timeout = starttime+300 - os.time() + 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") + nixio.kill(pid, nixio.const.SIGTERM) + manifest_loader:close() + return nil + end - local r = manifest_loader:read(1024) - if not r or r == '' then - break - end - data = data .. r + local r = manifest_loader:read(1024) + if not r or r == '' then + break + end + data = data .. r - while data:match('\n') do - local line, rest = data:match('^([^\n]*)\n(.*)$') - data = rest + while data:match('\n') do + local line, rest = data:match('^([^\n]*)\n(.*)$') + data = rest - if not sep then - if line == '---' then - sep = true - else - table.insert(lines, line) + if not sep then + if line == '---' then + sep = true + else + table.insert(lines, line) - if line == ('BRANCH=' .. branch.name) then - branch_ok = true - end + if line == ('BRANCH=' .. branch.name) then + branch_ok = true + end - local date = line:match('^DATE=(.+)$') - local priority = line:match('^PRIORITY=([%d%.]+)$') - local model, version, checksum, filename = line:match('^([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)$') + local date = line:match('^DATE=(.+)$') + local priority = line:match('^PRIORITY=([%d%.]+)$') + local model, version, checksum, filename = line:match('^([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)$') - if date then - ret.date = autoupdater_util.parse_date(date) - elseif priority then - ret.priority = tonumber(priority) - elseif model == platform_info.get_image_name() then - ret.version = version - ret.checksum = checksum - ret.filename = filename - end - end - else - table.insert(sigs, line) - end - end - end - manifest_loader:close() + if date then + ret.date = autoupdater_util.parse_date(date) + elseif priority then + ret.priority = tonumber(priority) + elseif model == platform_info.get_image_name() then + ret.version = version + ret.checksum = checksum + ret.filename = filename + end + end + else + table.insert(sigs, line) + end + end + end + manifest_loader:close() - -- Do some very basic checks before checking the signatures - -- (as the signature verification is computationally expensive) - if not sep then - io.stderr:write('There seems to have gone something wrong downloading the manifest from ' .. mirror .. '\n') - return nil - end + -- Do some very basic checks before checking the signatures + -- (as the signature verification is computationally expensive) + if not sep then + io.stderr:write('There seems to have gone something wrong downloading the manifest from ' .. mirror .. '\n') + return nil + end - if not ret.date or not ret.priority then - io.stderr:write('The manifest downloaded from ' .. mirror .. ' is invalid (DATE or PRIORITY missing)\n') - return nil - end + if not ret.date or not ret.priority then + io.stderr:write('The manifest downloaded from ' .. mirror .. ' is invalid (DATE or PRIORITY missing)\n') + return nil + end - if not branch_ok then - io.stderr:write('Wrong branch. We are on ', branch.name, '.\n') - return nil - end + if not branch_ok then + io.stderr:write('Wrong branch. We are on ', branch.name, '.\n') + return nil + end - if not ret.version then - io.stderr:write('No matching firmware found (model ' .. platform_info.get_image_name() .. ')\n') - return nil - end + if not ret.version then + io.stderr:write('No matching firmware found (model ' .. platform_info.get_image_name() .. ')\n') + return nil + end - if not verify_lines(lines, sigs) then - io.stderr:write('Not enough valid signatures!\n') - return nil - end + if not verify_lines(lines, sigs) then + io.stderr:write('Not enough valid signatures!\n') + return nil + end - return ret + return ret end -- Downloads the firmware image from a mirror to a given output file local function fetch_firmware(mirror, filename, output) - -- 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 + -- 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 - return true + return true end -- Returns the computed update probability local function get_probability(date, priority) - local seconds = priority * 86400 - local diff = os.difftime(os.time(), date) + local seconds = priority * 86400 + local diff = os.difftime(os.time(), date) - 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. - -- 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 - io.stderr:write('Warning: clock seems to be incorrect.\n') + 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. + -- 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 + io.stderr:write('Warning: clock seems to be incorrect.\n') - 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 - return 0 - else - -- Will give 1 when priority == 0, and lower probabilities the higher the priority value is - -- (similar to the old static probability system) - return 0.75^priority - end + 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 + return 0 + else + -- Will give 1 when priority == 0, and lower probabilities the higher the priority value is + -- (similar to the old static probability system) + return 0.75^priority + end - elseif fallback then - if diff >= seconds + 86400 then - return 1 - else - return 0 - end + elseif fallback then + if diff >= seconds + 86400 then + return 1 + else + return 0 + end - elseif diff >= seconds then - return 1 + elseif diff >= seconds then + return 1 - else - 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 - -- (we all love continuously differentiable functions, right?) - return (-2)*x^3 + 3*x^2 - end + else + 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 + -- (we all love continuously differentiable functions, right?) + return (-2)*x^3 + 3*x^2 + end 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 upgrade_d_dir = '/usr/lib/autoupdater/upgrade.d' + local download_d_dir = '/usr/lib/autoupdater/download.d' + local abort_d_dir = '/usr/lib/autoupdater/abort.d' + local upgrade_d_dir = '/usr/lib/autoupdater/upgrade.d' - local manifest = read_manifest(mirror) - if not manifest then - return false - end + local manifest = read_manifest(mirror) + if not manifest then + return false + end - if not autoupdater_version.newer_than(manifest.version, old_version) then - io.stderr:write('No new firmware available.\n') - return true - end + if not autoupdater_version.newer_than(manifest.version, old_version) then + io.stderr:write('No new firmware available.\n') + return true + 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 - io.stderr:write('No autoupdate this time. Use -f to override.\n') - return true - end + 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') + return true + end - autoupdater_util.run_dir(download_d_dir) - collectgarbage() + 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 + local image = os.tmpname() + if not fetch_firmware(mirror, manifest.filename, image) then + autoupdater_util.run_dir(abort_d_dir) + return false + end - local popen = io.popen(string.format("exec sha512sum '%s'", image)) - local checksum = popen:read('*l'):match('^%x+') - popen:close() - 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 + local popen = io.popen(string.format("exec sha512sum '%s'", image)) + local checksum = popen:read('*l'):match('^%x+') + popen:close() + 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 - autoupdater_util.run_dir(upgrade_d_dir) + autoupdater_util.run_dir(upgrade_d_dir) - io.stderr:write('Upgrading firmware...\n') - local null = nixio.open('/dev/null', 'w+') - if null then - nixio.dup(null, nixio.stdin) - nixio.dup(null, nixio.stderr) - if null:fileno() > 2 then - null:close() - end - end + io.stderr:write('Upgrading firmware...\n') + local null = nixio.open('/dev/null', 'w+') + if null then + nixio.dup(null, nixio.stdin) + nixio.dup(null, nixio.stderr) + if null:fileno() > 2 then + null:close() + 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 - -- 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) + -- 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 + io.write('Failed to call sysupgrade?\n') + os.remove(image) + autoupdater_util.run_dir(abort_d_dir) + os.exit(1) end @@ -345,24 +345,24 @@ local lockfile = '/var/lock/autoupdater.lock' local lockfd = nixio.open(lockfile, 'w', 'rw-------') if not lockfd:lock('tlock') then - io.stderr:write(string.format( - "Unable to lock file %s. Make sure there is no other instance of the autoupdater running.\n", - lockfile, err - )) - os.exit(1) + io.stderr:write(string.format( + "Unable to lock file %s. Make sure there is no other instance of the autoupdater running.\n", + lockfile, err + )) + os.exit(1) end if #mirrors == 0 then - while #branch.mirror > 0 do - table.insert(mirrors, table.remove(branch.mirror, math.random(#branch.mirror))) - end + while #branch.mirror > 0 do + table.insert(mirrors, table.remove(branch.mirror, math.random(#branch.mirror))) + end end for k, mirror in ipairs(mirrors) do - if autoupdate(mirror) then - os.exit(0) - end + if autoupdate(mirror) then + os.exit(0) + end end io.stderr:write('No usable mirror found.\n')