OC-misc/partition/driveboot.lua

156 lines
4.0 KiB
Lua

return (function()
local component = component
function computer.getBootAddress()
return component.invoke(component.list("eeprom")(),"getData")
end
function computer.setBootAddress(a)
return component.invoke(component.list("eeprom")(),"setData",a)
end
local rv
local function getProxy(addr)
if type(addr) == "string" then
return component.proxy(addr)
end
return addr
end
local function aop(td,n,mn,...)
local rv
if td.getPosition then
local rts = td.getPosition()
if rts ~= n then
td.seek(n - rts)
end
rv = {td[mn](...)}
else
local rts = td.seek(-math.huge)
td.seek(n)
rv = {td[mn](...)}
td.seek(-math.huge)
td.seek(rts)
end
return table.unpack(rv)
end
local eformat = "c20c4>I4>I4"
function parsePartitions(s)
local rt = {}
for i = 1, s:len(), 32 do
local n, t, start, length = string.unpack(eformat, s, i)
n = n:gsub("\0", "")
if n ~= "" then
rt[#rt+1] = {n,t,start,length}
end
end
return rt
end
function getPartitions(drive)
local rv
if drive.type == "tape_drive" then
local ts = drive.getSize()
local lso = (math.floor(ts / 512) - 1) * 512
rv = parsePartitions(aop(drive, lso, "read", ts - lso))
else
rv = parsePartitions(drive.readSector(drive.getCapacity() / drive.getSectorSize()))
end
return rv[1][2] == "mtpt" and rv
end
local function offsetSector(part,sector)
if sector < 1 or sector > part[4] then error("invalid offset, not in a usable sector") end
return (part[3] - 1) + sector
end
local function readSector(drive,part,sector)
return drive.readSector(offsetSector(part,sector)):gsub("\0+$","")
end
local function readPart(drive,part)
local rv = ""
for i = 1, part[4] do
if drive.type == "tape_drive" then
rv=rv .. aop(drive, ((part[3]-2) + i)*512, "read", 512):gsub("\0+$","")
else
rv=rv .. readSector(drive,part,i)
end
end
return rv
end
local pB = computer.getBootAddress()
local candidates={pB,[pB] = true}
if not component.type(pB) then candidates[1] = nil end
for a,t in component.list() do
candidates[#candidates+1] = not candidates[a] and (t == "drive" or t == "filesystem" or t == "tape_drive") and a or nil
candidates[a] = true
end
local function wL()
return false
end
local cL=wL
local ga, sa = component.list("gpu")(), component.list("screen")()
if ga and sa then
local g, cl = component.proxy(ga), 1
g.bind(sa)
g.setResolution(g.maxResolution())
function wL(s)
g.set(1,cl,s)
cl = cl + 1
end
function cL()
g.fill(1,1,160,50, " ")
cl = 1
end
local function drawOptions()
cL()
wL(string.format("SKS Enhanced BIOS - %0.0fK RAM",computer.totalMemory()/1024))
cl=cl+1
wL(tostring(#candidates).." devices, press listed key to select")
wL("key address type label")
for k,v in ipairs(candidates) do
wL(string.format("[%s] %s %10s %s",string.char(k+96),v:sub(1,8), component.type(v), component.invoke(v, "getLabel") or ""))
end
end
local to = computer.uptime() + 2.5
drawOptions()
repeat
local tE = {computer.pullSignal(to - computer.uptime())}
if tE[1] == "key_down" and candidates[tE[3]-96] then
to = computer.uptime() + 2.5
table.insert(candidates, 1, table.remove(candidates,tE[3]-96))
drawOptions()
end
until computer.uptime() >= to
end
for i,a in ipairs(candidates) do
computer.beep(("."):rep(i))
wL("Attempting to load from "..a)
local d = getProxy(a)
if type(d) == "table" and d.type == "filesystem" then
if d.exists("/init.lua") then
local rb, b = "", ""
local f = d.open("/init.lua","rb")
repeat
b = d.read(f, 2048) or ""
rb = rb .. b
until b == ""
d.close(f)
local rv = load(rb,a.."/init.lua")
if rv then
computer.beep("-")
computer.setBootAddress(a)
cL()
return rv
end
end
elseif type(d) == "table" and (d.type == "drive" or d.type == "tape_drive") then
for k,v in ipairs(getPartitions(d)) do
if v[2] == "boot" then
local rv = load(readPart(d,v), a.."/"..tostring(k))
if rv then
computer.beep("-")
computer.setBootAddress(a)
cL()
return rv
end
end
end
end
end
error("no bootable devices found")
end)()()