wot
This commit is contained in:
commit
c9c05221d9
2
.buildactions/00_setup.lua
Normal file
2
.buildactions/00_setup.lua
Normal file
@ -0,0 +1,2 @@
|
||||
os.execute("mkdir -p build")
|
||||
os.execute("rm -rf build/*")
|
211
.buildactions/01_velx.lua
Normal file
211
.buildactions/01_velx.lua
Normal file
@ -0,0 +1,211 @@
|
||||
-- VELX builder
|
||||
|
||||
--[[----------------------------------------------------------------------------
|
||||
LZSS - encoder / decoder
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
--]]----------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
local M = {}
|
||||
local string, table = string, table
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local POS_BITS = 12
|
||||
local LEN_BITS = 16 - POS_BITS
|
||||
local POS_SIZE = 1 << POS_BITS
|
||||
local LEN_SIZE = 1 << LEN_BITS
|
||||
local LEN_MIN = 3
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function M.compress(input)
|
||||
local offset, output = 1, {}
|
||||
local window = ''
|
||||
|
||||
local function search()
|
||||
for i = LEN_SIZE + LEN_MIN - 1, LEN_MIN, -1 do
|
||||
local str = string.sub(input, offset, offset + i - 1)
|
||||
local pos = string.find(window, str, 1, true)
|
||||
if pos then
|
||||
return pos, str
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while offset <= #input do
|
||||
local flags, buffer = 0, {}
|
||||
|
||||
for i = 0, 7 do
|
||||
if offset <= #input then
|
||||
local pos, str = search()
|
||||
if pos and #str >= LEN_MIN then
|
||||
local tmp = ((pos - 1) << LEN_BITS) | (#str - LEN_MIN)
|
||||
buffer[#buffer + 1] = string.pack('>I2', tmp)
|
||||
else
|
||||
flags = flags | (1 << i)
|
||||
str = string.sub(input, offset, offset)
|
||||
buffer[#buffer + 1] = str
|
||||
end
|
||||
window = string.sub(window .. str, -POS_SIZE)
|
||||
offset = offset + #str
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if #buffer > 0 then
|
||||
output[#output + 1] = string.char(flags)
|
||||
output[#output + 1] = table.concat(buffer)
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(output)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function M.decompress(input)
|
||||
local offset, output = 1, {}
|
||||
local window = ''
|
||||
|
||||
while offset <= #input do
|
||||
local flags = string.byte(input, offset)
|
||||
offset = offset + 1
|
||||
|
||||
for i = 1, 8 do
|
||||
local str = nil
|
||||
if (flags & 1) ~= 0 then
|
||||
if offset <= #input then
|
||||
str = string.sub(input, offset, offset)
|
||||
offset = offset + 1
|
||||
end
|
||||
else
|
||||
if offset + 1 <= #input then
|
||||
local tmp = string.unpack('>I2', input, offset)
|
||||
offset = offset + 2
|
||||
local pos = (tmp >> LEN_BITS) + 1
|
||||
local len = (tmp & (LEN_SIZE - 1)) + LEN_MIN
|
||||
str = string.sub(window, pos, pos + len - 1)
|
||||
end
|
||||
end
|
||||
flags = flags >> 1
|
||||
if str then
|
||||
output[#output + 1] = str
|
||||
window = string.sub(window .. str, -POS_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(output)
|
||||
end
|
||||
|
||||
|
||||
local function struct(tbl)
|
||||
local pat = tbl.endian or "="
|
||||
local args = {}
|
||||
for i=1, #tbl do
|
||||
local a, b = pairs(tbl[i])
|
||||
local k, v = a(b)
|
||||
args[i] = k
|
||||
pat = pat .. v
|
||||
end
|
||||
return setmetatable({}, {__call=function(_, arg)
|
||||
--checkArg(1, arg, "string", "table")
|
||||
if (type(arg) == "string") then
|
||||
local sval = {string.unpack(pat, arg)}
|
||||
local rtn = {}
|
||||
for i=1, #args do
|
||||
rtn[args[i]] = sval[i]
|
||||
end
|
||||
return rtn, sval[#sval]
|
||||
elseif (type(arg) == "table") then
|
||||
local sval = {}
|
||||
for i=1, #args do
|
||||
sval[i] = arg[args[i]]
|
||||
end
|
||||
return string.pack(pat, unpack(sval))
|
||||
end
|
||||
end, __len=function()
|
||||
return string.packsize(pat)
|
||||
end})
|
||||
end
|
||||
|
||||
|
||||
local velx_spec = struct {
|
||||
endian = "<",
|
||||
{magic="c5"},
|
||||
{fver="B"},
|
||||
{compression="B"},
|
||||
{lver="B"},
|
||||
{os="B"},
|
||||
{arctype="c4"},
|
||||
{psize="I3"},
|
||||
{lsize="I3"},
|
||||
{ssize="I3"},
|
||||
{rsize="I4"}
|
||||
}
|
||||
|
||||
local function velx_multistep(path, arcpath, args, steps)
|
||||
local shell_args = ""
|
||||
for k, v in pairs(args) do
|
||||
shell_args = shell_args .. k .. "=\"".. v .."\" "
|
||||
end
|
||||
steps.precomp()
|
||||
local h = io.popen(shell_args.."luacomp "..path, "r")
|
||||
local prog = h:read("*a")
|
||||
h:close()
|
||||
prog = steps.postcomp(prog)
|
||||
steps.prearc()
|
||||
local arc = ""
|
||||
if arcpath then
|
||||
h = io.popen("find "..arcpath.." -depth | tsar -o", "r")
|
||||
arc = h:read("*a")
|
||||
h:close()
|
||||
steps.postarc()
|
||||
end
|
||||
if (not args.noz) then
|
||||
steps.prez()
|
||||
prog = M.compress(prog)
|
||||
steps.postz()
|
||||
end
|
||||
local header = velx_spec({
|
||||
magic = "\27VelX",
|
||||
compression = (args.noz and 0) or 1,
|
||||
lver = 0x53,
|
||||
fver = 1,
|
||||
os = 0x7F,
|
||||
psize = #prog,
|
||||
lsize=0,
|
||||
ssize=0,
|
||||
rsize=#arc,
|
||||
arctype=(arcpath and "tsar") or ""
|
||||
})
|
||||
return header .. prog .. arc
|
||||
end
|
||||
|
||||
local function velx(path, arcpath, args)
|
||||
return velx_multistep(path, arcpath, args, {
|
||||
precomp = function()end,
|
||||
postcomp = function(prog) return prog end,
|
||||
prearc = function()end,
|
||||
postarc = function()end,
|
||||
prez = function()end,
|
||||
postz = function()end,
|
||||
})
|
||||
end
|
50
.buildactions/11_kernel.lua
Normal file
50
.buildactions/11_kernel.lua
Normal file
@ -0,0 +1,50 @@
|
||||
local TSUKI_RELEASE = "0.0.1"
|
||||
local tz = os.date("%z")
|
||||
tz = tz:sub(1, 3)..":"..tz:sub(4)
|
||||
local TSUKI_VERSION = "Lua 5.3 "..os.date("%Y-%m-%dT%H:%M:%S")..tz
|
||||
local TSUKI_TARGET = os.getenv("TSUKI_TARGET") or "OC"
|
||||
|
||||
function actions.kernel(dbg)
|
||||
os.execute("mkdir -p build/kernel")
|
||||
print("Compiling kernel...")
|
||||
local h = io.open("build/kernel/tkrnl.velx", "wb")
|
||||
h:write(velx_multistep("ksrc/init.lua", ".doc", {
|
||||
TSUKI_RELEASE = TSUKI_RELEASE,
|
||||
TSUKI_VERSION = TSUKI_VERSION,
|
||||
TSUKI_TARGET = TSUKI_TARGET,
|
||||
PRINT_DMESG_LEVEL = ((dbg and 0) or 1)
|
||||
}, {
|
||||
precomp = function()
|
||||
print("Compiling kernel...")
|
||||
end,
|
||||
postcomp = function(krnl)
|
||||
os.execute("mkdir .doc")
|
||||
local h = io.open("build/kernel/debug.lua", "w")
|
||||
h:write(krnl)
|
||||
h:close()
|
||||
print("Generating docs and stripping comments...")
|
||||
h = io.popen("lua utils/gendocs.lua .doc 2>.ktmp", "w")
|
||||
h:write(krnl)
|
||||
h:close()
|
||||
h = io.open(".ktmp", "rb")
|
||||
local data = h:read("*a")
|
||||
h:close()
|
||||
os.execute("rm -rf .ktmp")
|
||||
return data
|
||||
end,
|
||||
prearc = function()
|
||||
print("Storing docs...")
|
||||
end,
|
||||
postarc = function()
|
||||
os.execute("rm -rf .doc")
|
||||
end,
|
||||
prez = function()
|
||||
print("Compressing kernel...")
|
||||
end,
|
||||
postz = function()
|
||||
print("Writing kernel out...")
|
||||
end
|
||||
}))
|
||||
end
|
||||
|
||||
actions[#actions+1] = "kernel"
|
7
.buildactions/20_crescent.lua
Normal file
7
.buildactions/20_crescent.lua
Normal file
@ -0,0 +1,7 @@
|
||||
function actions.crescent()
|
||||
os.execute("mkdir -p build/crescent")
|
||||
os.execute("cd extras; lua ../utils/mkvelx.lua crescent/init.lua ../build/crescent/boot.velx")
|
||||
os.execute("cp extras/crescent/bootvelxloader.lua build/crescent/init.lua")
|
||||
end
|
||||
|
||||
actions[#actions+1] = "crescent"
|
7
.buildactions/30_velxboot.lua
Normal file
7
.buildactions/30_velxboot.lua
Normal file
@ -0,0 +1,7 @@
|
||||
function actions.velxboot()
|
||||
os.execute("mkdir -p build/velxboot")
|
||||
os.execute("cd extras; luacomp velxboot/init.lua -O ../build/velxboot/bios.lua")
|
||||
os.execute("cd extras; luacomp velxboot/flashvelxboot.lua -O ../build/velxboot/flashvelxboot.lua")
|
||||
end
|
||||
|
||||
actions[#actions+1] = "velxboot"
|
37
.buildactions/40_coreutils.lua
Normal file
37
.buildactions/40_coreutils.lua
Normal file
@ -0,0 +1,37 @@
|
||||
do
|
||||
--local coreutils = {}
|
||||
--local function add_coreutil(name, outfolder, args)
|
||||
-- args = args or {}
|
||||
-- if not os.execute("[[ -d build/coreutils/"..outfolder.." ]]") then
|
||||
-- os.execute("mkdir -p build/coreutils/"..outfolder)
|
||||
-- end
|
||||
-- actions["coreutil_"..name] = function()
|
||||
-- local data = velx("coreutils/"..name..".lua", nil, args)
|
||||
-- local h = io.open("build/coreutils/"..outfolder.."/"..name..".velx", "w")
|
||||
-- h:write(data)
|
||||
-- h:close()
|
||||
-- end
|
||||
-- coreutils[#coreutils+1] = name
|
||||
--end
|
||||
|
||||
--add_coreutil("init", "sbin")
|
||||
--add_coreutil("shutdown", "sbin")
|
||||
--add_coreutil("sh", "sbin")
|
||||
--add_coreutil("uname", "sbin")
|
||||
|
||||
--function actions.coreutils()
|
||||
-- for i=1, #coreutils do
|
||||
-- actions["coreutil_"..coreutils[i]]()
|
||||
-- end
|
||||
--end
|
||||
local version = "0.1"
|
||||
function actions.coreutils()
|
||||
print("Building coreutils...")
|
||||
os.execute("mkdir -p build/coreutils")
|
||||
local sks = io.open("build/coreutils/sks.velx", "w")
|
||||
sks:write(velx("coreutils/multicall.lua", false, {
|
||||
SKS_COREUTILS_VERSION = version
|
||||
}))
|
||||
end
|
||||
actions[#actions+1] = "coreutils"
|
||||
end
|
5
.buildactions/fe_debug.lua
Normal file
5
.buildactions/fe_debug.lua
Normal file
@ -0,0 +1,5 @@
|
||||
function actions.debug()
|
||||
for i=1, #actions do
|
||||
actions[actions[i]](true)
|
||||
end
|
||||
end
|
5
.buildactions/ff_clean.lua
Normal file
5
.buildactions/ff_clean.lua
Normal file
@ -0,0 +1,5 @@
|
||||
function actions.clean()
|
||||
print("Cleaning up...")
|
||||
--os.execute("rm -rf .docs")
|
||||
--os.execute("rm -rf .ktmp")
|
||||
end
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/.doc
|
||||
.ktmp
|
||||
/build/**
|
27
build.lua
Normal file
27
build.lua
Normal file
@ -0,0 +1,27 @@
|
||||
local actions = {}
|
||||
|
||||
@[[local h = io.popen("ls .buildactions", "r")
|
||||
for line in h:lines() do]]
|
||||
--#include @[{".buildactions/"..line}]
|
||||
@[[end]]
|
||||
|
||||
--[[function actions.debug()
|
||||
actions.kernel(true)
|
||||
actions.crescent()
|
||||
actions.velxboot()
|
||||
actions.clean()
|
||||
end]]
|
||||
|
||||
function actions.all()
|
||||
for i=1, #actions do
|
||||
actions[actions[i]]()
|
||||
end
|
||||
end
|
||||
|
||||
if not arg[1] then
|
||||
arg[1] = "all"
|
||||
end
|
||||
|
||||
actions[arg[1]]()
|
||||
|
||||
print("Build complete.")
|
2
build.sh
Executable file
2
build.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env sh
|
||||
luacomp build.lua 2>/dev/null | lua - "$@"
|
57
coreutils/init.lua
Normal file
57
coreutils/init.lua
Normal file
@ -0,0 +1,57 @@
|
||||
local kargs = ...
|
||||
local kio = kernel.kmode_run("return kio")
|
||||
local tty = kernel.kmode_run("return tty")
|
||||
local exec = kernel.kmode_run("return exec")
|
||||
local thd = require("thread")
|
||||
local fs = require("filesystem")
|
||||
local security = require("security")
|
||||
|
||||
kernel.dmesg(kernel.loglevel.INFO, "ksysinit started")
|
||||
local function run_hooks(hook, args)
|
||||
local hooks = fs.list("/etc/ksysinit/"..hook)
|
||||
for i=1, #hooks do
|
||||
local path = fs.resolve("/etc/ksysinit/"..hook.."/"..hooks[i])
|
||||
local stat = fs.stat(path)
|
||||
if (stat.mode == "file" and stat.uid == 0 and stat.gid == 0 and mode & 2 == 0) then
|
||||
local f, err = loadfile(path)
|
||||
if not f then
|
||||
kernel.dmesg(kernel.loglevel.WARNING, "Failed to load startup hook `"..hooks[i].."': "..err)
|
||||
goto continue
|
||||
end
|
||||
xpcall(function()
|
||||
f(table.unpack(args))
|
||||
end, function(err)
|
||||
kernel.dmesg(kernel.loglevel.ERROR, "Error in startup hook `"..hooks[i].."': "..debug.traceback(err))
|
||||
end)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
kernel.dmesg(kernel.loglevel.INFO, "running startup hooks")
|
||||
run_hooks("startup", {})
|
||||
|
||||
kernel.dmesg(kernel.loglevel.INFO, "starting ttys")
|
||||
for i=1, tonumber(kargs["tty.count"]) or 1 do
|
||||
local pty = tty.get(i)
|
||||
exec.loadfile("/sbin/login.velx", true, {
|
||||
uid = 0,
|
||||
gid = 0,
|
||||
tty = pty
|
||||
})
|
||||
end
|
||||
|
||||
-- Now we wait for shutdown or other things
|
||||
while true do
|
||||
local siginfo = kernel.sig_pull()
|
||||
if siginfo.type == "shutdown" then
|
||||
run_hooks("shutdown", {})
|
||||
kernel.kmode_run([[computer.shutdown()]])
|
||||
elseif siginfo.type == "reboot" then
|
||||
run_hooks("shutdown", {})
|
||||
kernel.kmode_run([[computer.shutdown(true)]])
|
||||
elseif siginfo.type == "ipc" and siginfo.message[1] == "svcrun" and security.hasperm("svc", siginfo.uid, siginfo.gid) then
|
||||
table.pack(table.unpack(siginfo.message, 4))
|
||||
run_hooks("services/"..siginfo.message[2].."/"..siginfo.message[3], table.pack(table.unpack(siginfo.message, 4)))
|
||||
end
|
||||
end
|
45
coreutils/multicall.lua
Normal file
45
coreutils/multicall.lua
Normal file
@ -0,0 +1,45 @@
|
||||
local calls = {}
|
||||
|
||||
local function version_info()
|
||||
print("SKS Coreutils version $[{SKS_COREUTILS_VERSION}]")
|
||||
end
|
||||
|
||||
@[[function add_util(name)]]
|
||||
calls["@[{name}]"] = function(...)
|
||||
--#include @[{"coreutils/"..name..".lua"}]
|
||||
end
|
||||
@[[end]]
|
||||
|
||||
@[[
|
||||
add_util("init")
|
||||
add_util("reboot")
|
||||
add_util("sh")
|
||||
add_util("shutdown")
|
||||
add_util("svc-ctl")
|
||||
add_util("uname")
|
||||
]]
|
||||
|
||||
calls.sks = function(prog, ...)
|
||||
if not prog then
|
||||
version_info()
|
||||
print("SKS Coreutils multicall binary.\n")
|
||||
print("Calls:")
|
||||
local t = {}
|
||||
for k, v in pairs(calls) do
|
||||
t[#t+1] = k
|
||||
end
|
||||
print(table.concat(t, " "))
|
||||
return 0
|
||||
end
|
||||
return calls[prog](...)
|
||||
end
|
||||
|
||||
setmetatable(calls, {__index=function(_, i)
|
||||
return function()
|
||||
io.stderr:write("call "..i.." not found. run `sks' without args for list of calls.\n")
|
||||
end
|
||||
end})
|
||||
|
||||
local call = os.getenv("_"):match("/(.+)%.[^%.]+")
|
||||
|
||||
return calls[call](...)
|
5
coreutils/reboot.lua
Normal file
5
coreutils/reboot.lua
Normal file
@ -0,0 +1,5 @@
|
||||
if (kernel) then
|
||||
kernel.sig_push {
|
||||
sigtype = "shutdown"
|
||||
}
|
||||
end
|
0
coreutils/sh.lua
Normal file
0
coreutils/sh.lua
Normal file
10
coreutils/shutdown.lua
Normal file
10
coreutils/shutdown.lua
Normal file
@ -0,0 +1,10 @@
|
||||
if (kernel) then
|
||||
if (os.getenv("_"):match("reboot.velx")) then
|
||||
kernel.sig_push {sigtype = "reboot"}
|
||||
else
|
||||
kernel.sig_push {sigtype = "shutdown"}
|
||||
end
|
||||
else
|
||||
io.stderr:write("must be run as root\n")
|
||||
os.exit(-1)
|
||||
end
|
6
coreutils/svc-ctl.lua
Normal file
6
coreutils/svc-ctl.lua
Normal file
@ -0,0 +1,6 @@
|
||||
if (kernel) then
|
||||
--#include "coreutils/svc-ctl/init.lua"
|
||||
else
|
||||
io.stderr:write("must be run as root\n")
|
||||
os.exit(-1)
|
||||
end
|
26
coreutils/svc-ctl/init.lua
Normal file
26
coreutils/svc-ctl/init.lua
Normal file
@ -0,0 +1,26 @@
|
||||
local args = {...}
|
||||
local thread = require("thread")
|
||||
local ipc = require("ipc")
|
||||
local fs = require("filesystem")
|
||||
|
||||
if not args[1] then
|
||||
local svcs = {}
|
||||
for f in fs.list("/etc/ksysinit/services") do
|
||||
svcs[#svcs+1] = f
|
||||
end
|
||||
print(table.concat(svcs, ", "))
|
||||
return 0
|
||||
elseif args[1] and not args[2] then
|
||||
local svcs = {}
|
||||
for f in fs.list("/etc/ksysinit/services/"..args[1]) do
|
||||
svcs[#svcs+1] = f
|
||||
end
|
||||
print(table.concat(svcs, ", "))
|
||||
return 0
|
||||
elseif not fs.exists("/etc/ksysinit/services/"..args[1].."/"..args[2]) then
|
||||
io.stderr:write("hook `"..args[2].."' not found for `"..args[1].."'\n")
|
||||
return 1
|
||||
else
|
||||
local proc = thread.get("/sbin/init")
|
||||
ipc.send(proc, "svcrun", args[1], args[2])
|
||||
end
|
58
coreutils/uname.lua
Normal file
58
coreutils/uname.lua
Normal file
@ -0,0 +1,58 @@
|
||||
local sharg = require("sh_arg")
|
||||
local args = sharg({
|
||||
name = "uname",
|
||||
desc = [[Print certain system information. With no OPTION, same as -s]],
|
||||
options = {
|
||||
{"kernel-name", "s", "print the kernel name"},
|
||||
{"nodename", "n", "print the network node hostname"},
|
||||
{"kernel-release", "r", "print the kernel release"},
|
||||
{"kernel-version", "v", "print the kernel release"},
|
||||
{"machine", "m", "print the machine hardware name"},
|
||||
{"operating-system", "o", "print the operating system"},
|
||||
{"version", false, "output version information and exit"}
|
||||
},
|
||||
}, ...)
|
||||
|
||||
if (args.version) then
|
||||
version_info()
|
||||
return 0
|
||||
end
|
||||
|
||||
if (args.a or args.all) then
|
||||
args.s = true
|
||||
args.r = true
|
||||
args.v = true
|
||||
args.n = true
|
||||
args.m = true
|
||||
args.o = true
|
||||
end
|
||||
|
||||
if table.select("#", ...) == 0 then
|
||||
args.s = true
|
||||
end
|
||||
|
||||
if (args.s) then
|
||||
io.stdout:write(_KINFO.name.." ")
|
||||
end
|
||||
|
||||
if (args.n) then
|
||||
io.stdout:write(os.getenv("HOSTNAME").." ")
|
||||
end
|
||||
|
||||
if (args.r) then
|
||||
io.stdout:write(_KINFO.release.." ")
|
||||
end
|
||||
|
||||
if (args.v) then
|
||||
io.stdout:write(_KINFO.version.." ")
|
||||
end
|
||||
|
||||
if (args.m) then
|
||||
io.stdout:write(_KINFO.machine.." ")
|
||||
end
|
||||
|
||||
if (args.o) then
|
||||
io.stdout:write("SKS/Tsuki ")
|
||||
end
|
||||
|
||||
io.stdout:write("\n")
|
0
docs/foxfs.md
Normal file
0
docs/foxfs.md
Normal file
22
docs/kargs.md
Normal file
22
docs/kargs.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Kernel Arguments
|
||||
|
||||
/boot/kernel/tsuki-0.1.velx [arguments ...]
|
||||
|
||||
## --security
|
||||
This argument changes the security enviroment of the Tsuki kernel.
|
||||
|
||||
### --security=none
|
||||
This disables most of Tsuki's security modules, leaving the system in a vulnerable state.
|
||||
|
||||
### --security=noverify
|
||||
This disables executable verification. This is default.
|
||||
|
||||
### --security=full
|
||||
This enables all security features.
|
||||
|
||||
### --security=permissive
|
||||
This makes all security errors into logged messages.
|
||||
|
||||
## --root=partspec
|
||||
This mounts the partition as the root (`/`). An example partspec would be `osdi(f81aa211-3552-4196-91f6-57cc51c3ebfb,2)`
|
||||
|
16
extras/bootloader/init.lua
Normal file
16
extras/bootloader/init.lua
Normal file
@ -0,0 +1,16 @@
|
||||
local eeprom = component.proxy(component.list("eeprom")())
|
||||
local function lzss_decompress(a)local b,c,d,e,j,i,h,g=1,'',''while b<=#a do
|
||||
e=c.byte(a,b)b=b+1
|
||||
for k=0,7 do h=c.sub
|
||||
g=h(a,b,b)if e>>k&1<1 and b<#a then
|
||||
i=c.unpack('>I2',a,b)j=1+(i>>4)g=h(d,j,j+(i&15)+2)b=b+1
|
||||
end
|
||||
b=b+1
|
||||
c=c..g
|
||||
d=h(d..g,-4^6)end
|
||||
end
|
||||
return c end
|
||||
|
||||
local drive, part = eeprom.getData():match("^([%x%-]+);(%d)$")
|
||||
part = tonumber(part)
|
||||
|
16
extras/crescent/bootvelxloader.lua
Normal file
16
extras/crescent/bootvelxloader.lua
Normal file
@ -0,0 +1,16 @@
|
||||
local fs = component.proxy(computer.getBootAddress())
|
||||
local f = fs.open("boot.velx")
|
||||
fs.seek(f, "set", 14)
|
||||
local psize = string.unpack("<I3", fs.read(f, 3))
|
||||
fs.seek(f, "set", 27)
|
||||
local rdat = psize
|
||||
local dat = ""
|
||||
local buf = ""
|
||||
repeat
|
||||
buf = fs.read(f, rdat)
|
||||
if (buf) then
|
||||
dat = dat .. buf
|
||||
end
|
||||
rdat = psize - #dat
|
||||
until rdat == 0 or not buf or buf == ""
|
||||
load(dat, "=boot.velx")()
|
53
extras/crescent/init.lua
Normal file
53
extras/crescent/init.lua
Normal file
@ -0,0 +1,53 @@
|
||||
@[[if not svar.get("CRESCENT_KARGS") then
|
||||
svar.set("CRESCENT_KARGS", "")
|
||||
end]]
|
||||
|
||||
local version = "1.0"
|
||||
|
||||
local gpu = component.list("gpu")()
|
||||
local w, h
|
||||
local screen = component.list('screen')()
|
||||
for address in component.list('screen') do
|
||||
if #component.invoke(address, 'getKeyboards') > 0 then
|
||||
screen = address
|
||||
end
|
||||
end
|
||||
local cls = function()end
|
||||
if gpu and screen then
|
||||
component.invoke(gpu, "bind", screen)
|
||||
w, h = component.invoke(gpu, "getResolution")
|
||||
component.invoke(gpu, "setResolution", w, h)
|
||||
component.invoke(gpu, "setBackground", 0x000000)
|
||||
component.invoke(gpu, "setForeground", 0xFFFFFF)
|
||||
component.invoke(gpu, "fill", 1, 1, w, h, " ")
|
||||
cls = function()component.invoke(gpu,"fill", 1, 1, w, h, " ")end
|
||||
end
|
||||
local y = 1
|
||||
local function status(msg)
|
||||
if gpu and screen then
|
||||
component.invoke(gpu, "set", 1, y, msg)
|
||||
if y == h then
|
||||
component.invoke(gpu, "copy", 1, 2, w, h - 1, 0, -1)
|
||||
component.invoke(gpu, "fill", 1, h, w, 1, " ")
|
||||
else
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local loadspin = 1
|
||||
local spins = {
|
||||
"-", "\\", "|", "/"
|
||||
}
|
||||
|
||||
local function lsc()
|
||||
loadspin = (loadspin % 4) + 1
|
||||
return spins[loadspin]
|
||||
end
|
||||
|
||||
--#include "crescent/velx.lua"
|
||||
--#include "crescent/tsar.lua"
|
||||
--#include "crescent/loader.lua"
|
||||
|
||||
status("crescent loader v"..version)
|
||||
boot_kernel("--root=$ --security=none"..$(CRESCENT_KARGS))
|
7
extras/crescent/loader.lua
Normal file
7
extras/crescent/loader.lua
Normal file
@ -0,0 +1,7 @@
|
||||
function boot_kernel(kargs)
|
||||
local knl, env = load_velx(computer.getBootAddress(), "kernel.velx")
|
||||
local iramfs = load_tsar(computer.getBootAddress(), "initramfs.tsar")
|
||||
env._ARCHIVE = iramfs
|
||||
status("kernel.velx "..kargs)
|
||||
knl(kargs)
|
||||
end
|
97
extras/crescent/tsar.lua
Normal file
97
extras/crescent/tsar.lua
Normal file
@ -0,0 +1,97 @@
|
||||
local magic = 0x5f7d
|
||||
local magic_rev = 0x7d5f
|
||||
local header_fmt = "I2I2I2I2I2I6I6"
|
||||
local en = string.unpack("=I2", string.char(0x7d, 0x5f)) == magic -- true = LE, false = BE
|
||||
local function get_end(e)
|
||||
return (e and "<") or ">"
|
||||
end
|
||||
local function read_header(dat)
|
||||
local e = get_end(en)
|
||||
local m = string.unpack(e.."I2", dat)
|
||||
if m ~= magic and m ~= magic_rev then return nil, "bad magic" end
|
||||
if m ~= magic then
|
||||
e = get_end(not en)
|
||||
end
|
||||
local ent = {}
|
||||
ent.magic, ent.namesize, ent.mode, ent.uid, ent.gid, ent.filesize, ent.mtime = string.unpack(e..header_fmt, dat)
|
||||
return ent
|
||||
end
|
||||
|
||||
local arc = {}
|
||||
|
||||
function arc:fetch(path)
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name == path and self.tbl[i].mode & 32768 > 0) then
|
||||
self.seek(self.tbl[i].pos-self.seek(0))
|
||||
return self.read(self.tbl[i].filesize), self.tbl[i]
|
||||
end
|
||||
end
|
||||
return nil, "file not found"
|
||||
end
|
||||
|
||||
function arc:exists(path)
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name == path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function arc:list(path)
|
||||
if path:sub(#path) ~= "/" then path = path .. "/" end
|
||||
local ent = {}
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name:sub(1, #path) == path and not self.tbl[i].name:find("/", #path+1, false)) then
|
||||
ent[#ent+1] = self.tbl[i].name
|
||||
end
|
||||
end
|
||||
return ent
|
||||
end
|
||||
|
||||
function arc:close()
|
||||
self.close()
|
||||
end
|
||||
|
||||
function load_tsar(addr, path)
|
||||
local fs = component.proxy(addr)
|
||||
local h = fs.open(path)
|
||||
status("loading initramfs... "..lsc())
|
||||
local dat = ""
|
||||
local buf = ""
|
||||
repeat
|
||||
buf = fs.read(h, math.huge)
|
||||
if (buf) then
|
||||
dat = dat .. buf
|
||||
end
|
||||
y = y - 1
|
||||
status("loading initramfs... "..lsc())
|
||||
until not buf or buf == ""
|
||||
local idx = 1
|
||||
local function read(a)
|
||||
local dat = buf:sub(idx, idx+a-1)
|
||||
idx = idx + a
|
||||
return dat
|
||||
end
|
||||
local function seek(a)
|
||||
idx = idx + a
|
||||
return idx
|
||||
end
|
||||
local function close()end
|
||||
local tbl = {}
|
||||
local lname = ""
|
||||
while lname ~= "TRAILER!!!" do
|
||||
y = y - 1
|
||||
status("loading initramfs... "..lsc())
|
||||
local dat = read(22)
|
||||
local et = read_header(dat)
|
||||
et.name = read(et.namesize)
|
||||
et.pos = seek(et.namesize & 1)
|
||||
seek(et.filesize + (et.filesize & 1))
|
||||
lname = et.name
|
||||
if lname ~= "TRAILER!!!" then
|
||||
tbl[#tbl+1] = et
|
||||
end
|
||||
end
|
||||
return setmetatable({tbl = tbl, read = read, seek = seek, close = close}, {__index=arc})
|
||||
end
|
42
extras/crescent/velx.lua
Normal file
42
extras/crescent/velx.lua
Normal file
@ -0,0 +1,42 @@
|
||||
local function lzss_decompress(a)local b,c,d,e,j,i,h,g=1,'',''while b<=#a do
|
||||
e=c.byte(a,b)b=b+1
|
||||
for k=0,7 do h=c.sub
|
||||
g=h(a,b,b)if e>>k&1<1 and b<#a then
|
||||
i=c.unpack('>I2',a,b)j=1+(i>>4)g=h(d,j,j+(i&15)+2)b=b+1
|
||||
end
|
||||
b=b+1
|
||||
c=c..g
|
||||
d=h(d..g,-4^6)end
|
||||
end
|
||||
return c end
|
||||
|
||||
local function load_velx(addr, path)
|
||||
status("loading kernel... "..lsc())
|
||||
local fs = component.proxy(addr)
|
||||
local h = fs.open(path)
|
||||
local magic, fver, comp, lver, osid, psize = string.unpack("<c5BBBBxxxxI3xxxxxxxxxx", fs.read(h, 13))
|
||||
if (magic ~= "\27VelX" or fver ~= 1 or osid ~= 127) then
|
||||
return
|
||||
end
|
||||
local rdat = psize
|
||||
local dat = ""
|
||||
local buf = ""
|
||||
repeat
|
||||
buf = fs.read(h, rdat)
|
||||
if (buf) then
|
||||
dat = dat .. buf
|
||||
end
|
||||
rdat = psize - #dat
|
||||
y = y - 1
|
||||
status("loading kernel... "..lsc())
|
||||
until rdat == 0 or not buf or buf == ""
|
||||
y = y - 1
|
||||
status("loading kernel... ")
|
||||
if (comp == 1) then
|
||||
status("decompressing kernel...")
|
||||
dat = lzss_decompress(dat)
|
||||
end
|
||||
local env = {}
|
||||
env._G = env
|
||||
return load(dat, "="..path, "t", setmetatable(env, {__index=_G})), env
|
||||
end
|
72
extras/velxboot/flashvelxboot.lua
Normal file
72
extras/velxboot/flashvelxboot.lua
Normal file
@ -0,0 +1,72 @@
|
||||
local component = require("component")
|
||||
local computer = require("computer")
|
||||
print("Flashing velxboot...")
|
||||
component.eeprom.set([[
|
||||
--#include "velxboot/init.lua"
|
||||
]])
|
||||
component.eeprom.setData(computer.getBootAddress()..";boot.velx")
|
||||
print("Creating boot.velx...")
|
||||
local f = io.open("/init.lua")
|
||||
local prog = f:read("*a")
|
||||
f:close()
|
||||
|
||||
local function struct(tbl)
|
||||
local pat = tbl.endian or "="
|
||||
local args = {}
|
||||
for i=1, #tbl do
|
||||
local a, b = pairs(tbl[i])
|
||||
local k, v = a(b)
|
||||
args[i] = k
|
||||
pat = pat .. v
|
||||
end
|
||||
return setmetatable({}, {__call=function(_, arg)
|
||||
--checkArg(1, arg, "string", "table")
|
||||
if (type(arg) == "string") then
|
||||
local sval = {string.unpack(pat, arg)}
|
||||
local rtn = {}
|
||||
for i=1, #args do
|
||||
rtn[args[i]] = sval[i]
|
||||
end
|
||||
return rtn, sval[#sval]
|
||||
elseif (type(arg) == "table") then
|
||||
local sval = {}
|
||||
for i=1, #args do
|
||||
sval[i] = arg[args[i]]
|
||||
end
|
||||
return string.pack(pat, unpack(sval))
|
||||
end
|
||||
end, __len=function()
|
||||
return string.packsize(pat)
|
||||
end})
|
||||
end
|
||||
|
||||
|
||||
local velx_spec = struct {
|
||||
endian = "<",
|
||||
{magic="c5"},
|
||||
{fver="B"},
|
||||
{compression="B"},
|
||||
{lver="B"},
|
||||
{os="B"},
|
||||
{arctype="c4"},
|
||||
{psize="I3"},
|
||||
{lsize="I3"},
|
||||
{ssize="I3"},
|
||||
{rsize="I4"}
|
||||
}
|
||||
|
||||
f = io.open("/boot.velx", "wb")
|
||||
f:write(velx_spec({
|
||||
magic="\27VelX",
|
||||
fver=1,
|
||||
compression=0,
|
||||
lver=0x53,
|
||||
os=127,
|
||||
arctype="",
|
||||
psize=#prog
|
||||
lsize=0,
|
||||
ssize=0,
|
||||
rsize=0,
|
||||
}))
|
||||
f:write(prog)
|
||||
f:close()
|
67
extras/velxboot/init.lua
Normal file
67
extras/velxboot/init.lua
Normal file
@ -0,0 +1,67 @@
|
||||
local eeprom = component.proxy(component.list("eeprom")())
|
||||
local function lzss_decompress(a)local b,c,d,e,j,i,h,g=1,'',''while b<=#a do
|
||||
e=c.byte(a,b)b=b+1
|
||||
for k=0,7 do h=c.sub
|
||||
g=h(a,b,b)if e>>k&1<1 and b<#a then
|
||||
i=c.unpack('>I2',a,b)j=1+(i>>4)g=h(d,j,j+(i&15)+2)b=b+1
|
||||
end
|
||||
b=b+1
|
||||
c=c..g
|
||||
d=h(d..g,-4^6)end
|
||||
end
|
||||
return c end
|
||||
local function boot_velx(addr, path)
|
||||
local fs = component.proxy(addr)
|
||||
local h = fs.open(path)
|
||||
local magic, fver, comp, lver, osid, psize = string.unpack("<c5BBBBxxxxI3xxxxxxxxxx", fs.read(h, 13))
|
||||
if (magic ~= "\27VelX" or fver ~= 1 or osid ~= 127) then
|
||||
return
|
||||
end
|
||||
local rdat = psize
|
||||
local dat = ""
|
||||
local buf = ""
|
||||
repeat
|
||||
buf = fs.read(h, rdat)
|
||||
if (buf) then
|
||||
dat = dat .. buf
|
||||
end
|
||||
rdat = psize - #dat
|
||||
until rdat == 0 or not buf or buf == ""
|
||||
if (comp == 1) then
|
||||
dat = lzss_decompress(dat)
|
||||
end
|
||||
local baddr = addr
|
||||
local bpath = path
|
||||
function computer.getBootAddress()
|
||||
return baddr
|
||||
end
|
||||
function computer.getBootPath()
|
||||
return bpath
|
||||
end
|
||||
function computer.setBootAddress(a)
|
||||
eeprom.setData(a..";"..path)
|
||||
addr = a
|
||||
end
|
||||
function computer.setBootPath(p)
|
||||
eeprom.setData(addr..";"..p)
|
||||
path = p
|
||||
end
|
||||
assert(load(dat, "="..path))()
|
||||
end
|
||||
local config = eeprom.getData()
|
||||
local addr, path = config:match("^(.+);(.+)$")
|
||||
if not addr then
|
||||
addr = config
|
||||
path = "boot.velx"
|
||||
else
|
||||
return boot_velx(addr, path)
|
||||
end
|
||||
|
||||
if not component.invoke(addr, "exists", path) then
|
||||
for d in component.list("filesystem") do
|
||||
if (component.invoke(d, "exists", "boot.velx")) then
|
||||
eeprom.setData(d..";boot.velx")
|
||||
boot_velx(d, "boot.velx")
|
||||
end
|
||||
end
|
||||
end
|
21
ksrc/acl.lua
Normal file
21
ksrc/acl.lua
Normal file
@ -0,0 +1,21 @@
|
||||
local acl = {}
|
||||
do
|
||||
local acl = struct({
|
||||
meta = "B",
|
||||
id = "H"
|
||||
})
|
||||
|
||||
local function acl_readstream(stream)
|
||||
local a = acl(stream:read(#acl))
|
||||
local perm = stream:read(a.meta & 0x3f)
|
||||
local
|
||||
end
|
||||
|
||||
function acl.read(stream, dperm, gid, uid)
|
||||
|
||||
end
|
||||
|
||||
function _acl:get_effective_perm(id, group, perm)
|
||||
|
||||
end
|
||||
end
|
9
ksrc/ads.lua
Normal file
9
ksrc/ads.lua
Normal file
@ -0,0 +1,9 @@
|
||||
local ads = {}
|
||||
|
||||
function ads.get(path)
|
||||
|
||||
end
|
||||
|
||||
function ads.list(path)
|
||||
|
||||
end
|
10
ksrc/archives.lua
Normal file
10
ksrc/archives.lua
Normal file
@ -0,0 +1,10 @@
|
||||
local archives = {}
|
||||
archives.tsar = (function()
|
||||
--#include "ksrc/arcs/tsar/init.lua"
|
||||
end)()
|
||||
|
||||
function archive.parse(stream, atype)
|
||||
if archives[atype] then
|
||||
return archives[atype].read(stream)
|
||||
end
|
||||
end
|
0
ksrc/arcs/cpio/header.lua
Normal file
0
ksrc/arcs/cpio/header.lua
Normal file
124
ksrc/arcs/tsar/init.lua
Normal file
124
ksrc/arcs/tsar/init.lua
Normal file
@ -0,0 +1,124 @@
|
||||
local magic = 0x5f7d
|
||||
local magic_rev = 0x7d5f
|
||||
local header = "I2I2I2I2I2I6I6"
|
||||
|
||||
local function read_header(dat)
|
||||
local e = "<"
|
||||
local m = string.unpack("<I2", dat)
|
||||
if m ~= magic and m ~= magic_rev then return nil, "bad magic" end
|
||||
if m ~= magic then
|
||||
e = ">"
|
||||
end
|
||||
local ent = {}
|
||||
ent.magic, ent.namesize, ent.mode, ent.uid, ent.gid, ent.filesize, ent.mtime = string.unpack(e..header_fmt, dat)
|
||||
return ent
|
||||
end
|
||||
|
||||
local arc = {}
|
||||
|
||||
function arc:read(path)
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name == path and self.tbl[i].mode & 32768 > 0) then
|
||||
self.seek(self.tbl[i].pos-self.seek(0))
|
||||
return self.read(self.tbl[i].filesize), self.tbl[i]
|
||||
end
|
||||
end
|
||||
return nil, "file not found"
|
||||
end
|
||||
|
||||
function arc:exists(path)
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name == path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function arc:list(path)
|
||||
if path:sub(#path) ~= "/" then path = path .. "/" end
|
||||
local ent = {}
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name:sub(1, #path) == path and not self.tbl[i].name:find("/", #path+1, false)) then
|
||||
ent[#ent+1] = self.tbl[i].name
|
||||
end
|
||||
end
|
||||
return ent
|
||||
end
|
||||
|
||||
function arc:meta(path)
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name == path) then
|
||||
return self.tbl[i]
|
||||
end
|
||||
end
|
||||
return nil, "file not found"
|
||||
end
|
||||
|
||||
function arc:stream(path)
|
||||
for i=1, #self.tbl do
|
||||
if (self.tbl[i].name == path) then
|
||||
return kio.create_stream({dev=self.dev, start=self.tbl[i].pos, size=self.tbl[i].filesize, pos=1}, {
|
||||
read = function(self, amt)
|
||||
self.dev:seek("set", self.pos+self.start-1)
|
||||
if (self.pos+amt-1 > self.size) then
|
||||
amt = self.size-self.pos
|
||||
end
|
||||
local dat = self.dev:read(amt)
|
||||
self.pos = self.pos + #dat
|
||||
return dat
|
||||
end,
|
||||
seek = function(self, whence, amt)
|
||||
self.pos = kio.calc_seek(whence, amt, self.size, self.pos)
|
||||
return self.pos
|
||||
end,
|
||||
write = function(self)
|
||||
return kio.get_error(kio.errno.UNSUPPORTED_OPERATION)
|
||||
end,
|
||||
close = function(self)
|
||||
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function arc:trailer()
|
||||
self.dev:seek("set", self.tbl.trailer.pos)
|
||||
return self.dev:read(self.tbl.trailer.filesize)
|
||||
end
|
||||
|
||||
function arc:close()
|
||||
self.close()
|
||||
end
|
||||
|
||||
return {
|
||||
read = function(dev)
|
||||
local function read(a)
|
||||
return dev:read(a)
|
||||
end
|
||||
local function seek(a)
|
||||
return dev:seek("cur", a)
|
||||
end
|
||||
local function close()
|
||||
return dev:close()
|
||||
end
|
||||
local start = seek(0)
|
||||
local tbl = {}
|
||||
local lname = ""
|
||||
while lname ~= "TRAILER!!!" do
|
||||
local dat = read(22)
|
||||
local et = read_header(dat)
|
||||
et.name = read(et.namesize)
|
||||
et.pos = seek(et.namesize & 1)
|
||||
seek(et.filesize + (et.filesize & 1))
|
||||
lname = et.name
|
||||
if lname ~= "TRAILER!!!" then
|
||||
tbl[#tbl+1] = et
|
||||
else
|
||||
tbl.trailer = et
|
||||
end
|
||||
end
|
||||
return setmetatable({tbl = tbl, read = read, seek = seek, close = close, dev=dev, start=true}, {__index=arc})
|
||||
end
|
||||
}
|
1
ksrc/bios/unknown/detect.lua
Normal file
1
ksrc/bios/unknown/detect.lua
Normal file
@ -0,0 +1 @@
|
||||
return true
|
2
ksrc/bios/unknown/docs.lua
Normal file
2
ksrc/bios/unknown/docs.lua
Normal file
@ -0,0 +1,2 @@
|
||||
---@page unknown "Unknown"
|
||||
---@doc "This is for if Tsuki doesn't know what BIOS is in use."
|
4
ksrc/bios/unknown/info.lua
Normal file
4
ksrc/bios/unknown/info.lua
Normal file
@ -0,0 +1,4 @@
|
||||
return {
|
||||
name = "Unknown",
|
||||
version = {0, 0, 0, string="0.0.0"}
|
||||
}
|
0
ksrc/bios/unknown/quirks.lua
Normal file
0
ksrc/bios/unknown/quirks.lua
Normal file
1
ksrc/bios/zoryalegacy/detect.lua
Normal file
1
ksrc/bios/zoryalegacy/detect.lua
Normal file
@ -0,0 +1 @@
|
||||
return _LOAD == "Zorya"
|
6
ksrc/bios/zoryalegacy/docs.lua
Normal file
6
ksrc/bios/zoryalegacy/docs.lua
Normal file
@ -0,0 +1,6 @@
|
||||
---@page zorya_legacy "Zorya 1.x (Zorya Legacy)"
|
||||
---@doc "Zorya 1.x puts a few things in the global space that need to be removed. These include:"
|
||||
---@doc "- The OEFI library"
|
||||
---@doc "- The Zorya library"
|
||||
---@doc ""
|
||||
---@doc "Note: This *should* also apply to any forks of Zorya Legacy."
|
5
ksrc/bios/zoryalegacy/info.lua
Normal file
5
ksrc/bios/zoryalegacy/info.lua
Normal file
@ -0,0 +1,5 @@
|
||||
return {
|
||||
name = "Zorya",
|
||||
version = {_ZVER//1, tonumber(tostring(_ZVER):match("%.(%d+)")), _ZPAT, string = _ZVER..".".._ZPAT},
|
||||
oefiver = oefi.getAPIVersion()
|
||||
}
|
1
ksrc/bios/zoryalegacy/quirks.lua
Normal file
1
ksrc/bios/zoryalegacy/quirks.lua
Normal file
@ -0,0 +1 @@
|
||||
zorya = nil
|
1
ksrc/bios/zoryaneo/detect.lua
Normal file
1
ksrc/bios/zoryaneo/detect.lua
Normal file
@ -0,0 +1 @@
|
||||
return _BIOS == "Zorya NEO"
|
2
ksrc/bios/zoryaneo/docs.lua
Normal file
2
ksrc/bios/zoryaneo/docs.lua
Normal file
@ -0,0 +1,2 @@
|
||||
---@page zorya_neo "Zorya NEO (Zorya 2.0)"
|
||||
---@doc "There's not much to be done for Zorya NEO as the included Zorya module starts Tsuki with a nice enviroment."
|
5
ksrc/bios/zoryaneo/info.lua
Normal file
5
ksrc/bios/zoryaneo/info.lua
Normal file
@ -0,0 +1,5 @@
|
||||
return {
|
||||
name = "Zorya NEO",
|
||||
version = {_ZVER//1, tonumber(tostring(_ZVER):match("%.(%d+)")), _ZPAT, git = _ZGIT, string = _ZVSTR},
|
||||
loader = _ZLOADER
|
||||
}
|
0
ksrc/bios/zoryaneo/quirks.lua
Normal file
0
ksrc/bios/zoryaneo/quirks.lua
Normal file
30
ksrc/biosfixes.lua
Normal file
30
ksrc/biosfixes.lua
Normal file
@ -0,0 +1,30 @@
|
||||
---@section biosfixes "BIOS fixes"
|
||||
|
||||
@[[do
|
||||
local i=1]]
|
||||
local _biossupport = {}
|
||||
@[[function biosfix(bios)]]
|
||||
--#include @[{"ksrc/bios/"..bios.."/docs.lua"}]
|
||||
_biossupport["@[{bios}]"] = {
|
||||
quirks = function()
|
||||
--#include @[{"ksrc/bios/"..bios.."/quirks.lua"}]
|
||||
end,
|
||||
info = function()
|
||||
--#include @[{"ksrc/bios/"..bios.."/info.lua"}]
|
||||
end,
|
||||
detect = function()
|
||||
--#include @[{"ksrc/bios/"..bios.."/detect.lua"}]
|
||||
end,
|
||||
name = "@[{bios}]",
|
||||
id = @[{i}]
|
||||
}
|
||||
_biossupport[@[{i}]] = "@[{bios}]"
|
||||
@[[i=i+1]]
|
||||
@[[end]]
|
||||
|
||||
@[[biosfix("zoryalegacy")]]
|
||||
@[[biosfix("zoryaneo")]]
|
||||
|
||||
@[[biosfix("unknown")]]
|
||||
@[[biosfix = nil]]
|
||||
@[[end]]
|
5
ksrc/blk/eeprom.lua
Normal file
5
ksrc/blk/eeprom.lua
Normal file
@ -0,0 +1,5 @@
|
||||
local eeprom = {}
|
||||
|
||||
function eeprom.proxy(addr)
|
||||
|
||||
end
|
0
ksrc/blk/hdd.lua
Normal file
0
ksrc/blk/hdd.lua
Normal file
0
ksrc/blk/partition.lua
Normal file
0
ksrc/blk/partition.lua
Normal file
0
ksrc/blk/promcard.lua
Normal file
0
ksrc/blk/promcard.lua
Normal file
4
ksrc/blkdev.lua
Normal file
4
ksrc/blkdev.lua
Normal file
@ -0,0 +1,4 @@
|
||||
--#include "ksrc/blk/eeprom.lua"
|
||||
--#include "ksrc/blk/hdd.lua"
|
||||
--#include "ksrc/blk/partition.lua"
|
||||
--#include "ksrc/blk/promcard.lua"
|
5
ksrc/buffer.lua
Normal file
5
ksrc/buffer.lua
Normal file
@ -0,0 +1,5 @@
|
||||
local buffer = {}
|
||||
|
||||
local function create_buffer()
|
||||
|
||||
end
|
34
ksrc/exec.lua
Normal file
34
ksrc/exec.lua
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
local velx = (function()
|
||||
--#include "ksrc/execs/velx_spec/init.lua"
|
||||
end)()
|
||||
|
||||
local zlua = (function()
|
||||
--#include "ksrc/execs/zlua/init.lua"
|
||||
end)
|
||||
|
||||
local lua = (function()
|
||||
--#include "ksrc/execs/lua/init.lua"
|
||||
end)
|
||||
|
||||
-- Executable loading process:
|
||||
-- - Link
|
||||
-- - Load
|
||||
-- - Execute
|
||||
|
||||
function exec.loadfile(path, env, runinfo)
|
||||
local stat = vfs.stat(path)
|
||||
if (stat & 0x400 > 0) then
|
||||
runinfo.gid = stat.gid
|
||||
end
|
||||
if (stat & 0x800 > 0) then
|
||||
runinfo.uid = stat.uid
|
||||
end
|
||||
if (velx.identify(path)) then
|
||||
|
||||
elseif (zlua.identify(path)) then
|
||||
|
||||
else -- Load Lua...if we can.
|
||||
|
||||
end
|
||||
end
|
0
ksrc/execs/lua/init.lua
Normal file
0
ksrc/execs/lua/init.lua
Normal file
1
ksrc/execs/velx_spec/init.lua
Normal file
1
ksrc/execs/velx_spec/init.lua
Normal file
@ -0,0 +1 @@
|
||||
--#include "ksrc/execs/velx_spec/velxspec.lua"
|
86
ksrc/execs/velx_spec/velxspec.lua
Normal file
86
ksrc/execs/velx_spec/velxspec.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local velx_spec = struct {
|
||||
endian = "<",
|
||||
{magic="c5"},
|
||||
{fver="B"},
|
||||
{compression="B"},
|
||||
{lver="B"},
|
||||
{os="B"},
|
||||
{arctype="c4"},
|
||||
{psize="I3"},
|
||||
{lsize="I3"},
|
||||
{ssize="I3"},
|
||||
{rsize="I4"}
|
||||
}
|
||||
|
||||
local velx = {}
|
||||
|
||||
local exec = {}
|
||||
|
||||
function velx.identify(path)
|
||||
local h = io.open(path, "rb")
|
||||
local header = velx_spec(h:read(#velx_spec))
|
||||
h:close()
|
||||
return header.magic == "\27VelX"
|
||||
end
|
||||
|
||||
function velx.load(path)
|
||||
local h = io.open(path, "rb")
|
||||
local header = velx_spec(h:read(#velx_spec))
|
||||
local code = h:read(header.psize)
|
||||
h:seek("cur", lsize)
|
||||
local sig = h:read(header.ssize)
|
||||
end
|
||||
|
||||
function velx.verify(path)
|
||||
local h = io.open(path, "rb")
|
||||
local header = velx_spec(h:read(#velx_spec))
|
||||
local code = h:read(header.psize)
|
||||
h:seek("cur", lsize)
|
||||
local sig = h:read(header.ssize)
|
||||
h:close()
|
||||
return security.verify(code, sig)
|
||||
end
|
||||
|
||||
function exec:link()
|
||||
self.file:seek("set", #velx_spec+self.header.psize)
|
||||
local linkinfo = self.file:read(self.header.lsize)
|
||||
local linker = {}
|
||||
local pos = 1
|
||||
while true do
|
||||
local size = string.unpack("<H", linkinfo:sub(pos))
|
||||
pos = pos + 2
|
||||
local name = linkinfo:sub(pos, pos+size-1)
|
||||
pos = pos + size
|
||||
size = string.unpack("<H", linkinfo:sub(pos))
|
||||
pos = pos + 2
|
||||
local library = linkinfo:sub(pos, pos+size-1)
|
||||
pos = pos + size
|
||||
if (name == "" or library == "") then
|
||||
break
|
||||
end
|
||||
linker[#linker+1] = {name, library}
|
||||
end
|
||||
local linkscript = ""
|
||||
for i=1, #linker do
|
||||
linkscript = linkscript .. "local " .. linker[i][1] .. "=require(\"" .. linker[i][2] .. "\")\n"
|
||||
end
|
||||
self.code = linkscript .. self.code
|
||||
return true
|
||||
end
|
||||
|
||||
function exec:load()
|
||||
self.file:seek("set", #velx_spec)
|
||||
local code = self.file:read(self.header.psize)
|
||||
if (self.header.compression == 0) then
|
||||
self.code = code
|
||||
elseif (self.header.compression == 1) then
|
||||
self.code = lzss.decompress(self.code)
|
||||
else
|
||||
return nil, "invalid compression method"
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function exec:run(args, evar)
|
||||
system.load(self.code, args, system.getglobalenv({_ARCHIVE=self.arc}), system.getevars(evar))
|
||||
end
|
3
ksrc/execs/zlua/init.lua
Normal file
3
ksrc/execs/zlua/init.lua
Normal file
@ -0,0 +1,3 @@
|
||||
local zlua = {}
|
||||
|
||||
return {}
|
1
ksrc/fs/arcfs/init.lua
Normal file
1
ksrc/fs/arcfs/init.lua
Normal file
@ -0,0 +1 @@
|
||||
local afs = {}
|
21
ksrc/fs/foxfs/ads.lua
Normal file
21
ksrc/fs/foxfs/ads.lua
Normal file
@ -0,0 +1,21 @@
|
||||
function prox:getadses(path)
|
||||
local inode = fox_getnode(self, path)
|
||||
local adsl = fox_readdir(self, inode.ads)
|
||||
return adsl
|
||||
end
|
||||
|
||||
function prox:makeads(path, stream)
|
||||
|
||||
end
|
||||
|
||||
function prox:getads(path, stream)
|
||||
local inode = fox_getnode(self, path)
|
||||
local adsl = fox_readdir(self, inode.ads)
|
||||
for i=1, do
|
||||
if (adsl[i].name == stream) then
|
||||
local node = fox_getinode(self, adsl[i].inode)
|
||||
return {node=node, pos=1, mode=mode, dev=self}
|
||||
end
|
||||
end
|
||||
return nil, "not found"
|
||||
end
|
1
ksrc/fs/foxfs/blkstream.lua
Normal file
1
ksrc/fs/foxfs/blkstream.lua
Normal file
@ -0,0 +1 @@
|
||||
local blkstr = {}
|
14
ksrc/fs/foxfs/dir.lua
Normal file
14
ksrc/fs/foxfs/dir.lua
Normal file
@ -0,0 +1,14 @@
|
||||
local dirent = struct {
|
||||
endian="<",
|
||||
{inode="I4"},
|
||||
{name_size="H"},
|
||||
{etype="B"}
|
||||
}
|
||||
|
||||
local function fox_readdir(self, inode)
|
||||
|
||||
end
|
||||
|
||||
function prox:list(path)
|
||||
|
||||
end
|
21
ksrc/fs/foxfs/filehand.lua
Normal file
21
ksrc/fs/foxfs/filehand.lua
Normal file
@ -0,0 +1,21 @@
|
||||
function prox:open(path, mode)
|
||||
local node = fox_getnode(self, path)
|
||||
if not node then return nil, "file not found" end
|
||||
return {node=node, pos=1, mode=mode, dev=self}
|
||||
end
|
||||
|
||||
function prox:read(hand, amt)
|
||||
|
||||
end
|
||||
|
||||
function prox:write(hand, data)
|
||||
|
||||
end
|
||||
|
||||
function prox:seek(hand, amt)
|
||||
|
||||
end
|
||||
|
||||
function prox:close(hand)
|
||||
|
||||
end
|
0
ksrc/fs/foxfs/find_file.lua
Normal file
0
ksrc/fs/foxfs/find_file.lua
Normal file
22
ksrc/fs/foxfs/init.lua
Normal file
22
ksrc/fs/foxfs/init.lua
Normal file
@ -0,0 +1,22 @@
|
||||
local fox = {}
|
||||
do
|
||||
--#include "ksrc/fs/foxfs/inode.lua"
|
||||
--#include "ksrc/fs/foxfs/dir.lua"
|
||||
--#include "ksrc/fs/foxfs/superblock.lua"
|
||||
--#include "ksrc/fs/foxfs/blkstream.lua"
|
||||
|
||||
local prox = {}
|
||||
|
||||
function fox.proxy(dev)
|
||||
-- Read the superblock
|
||||
sb:seek("set", 1025)
|
||||
local sb = superblock(dev:read(#superblock))
|
||||
local prox = {
|
||||
super = sb
|
||||
}
|
||||
end
|
||||
|
||||
local function fox_getinode(prox, inode)
|
||||
|
||||
end
|
||||
end
|
33
ksrc/fs/foxfs/inode.lua
Normal file
33
ksrc/fs/foxfs/inode.lua
Normal file
@ -0,0 +1,33 @@
|
||||
local struct_inode = struct {
|
||||
endian = "<",
|
||||
{mode="H"},
|
||||
{uid="H"},
|
||||
{fsize="I6"},
|
||||
{atime="I6"},
|
||||
{ctime="I6"},
|
||||
{mtime="I6"},
|
||||
{dtime="I6"},
|
||||
{gid="H"},
|
||||
{sec_count="I4"},
|
||||
{flags="I4"},
|
||||
{osval="I4"},
|
||||
{dbp0="I4"},
|
||||
{dbp1="I4"},
|
||||
{dbp2="I4"},
|
||||
{dbp3="I4"},
|
||||
{dbp4="I4"},
|
||||
{dbp5="I4"},
|
||||
{dbp6="I4"},
|
||||
{dbp7="I4"},
|
||||
{dbp8="I4"},
|
||||
{dbp9="I4"},
|
||||
{dbp10="I4"},
|
||||
{dbp11="I4"},
|
||||
{sibp="I4"},
|
||||
{dibp="I4"},
|
||||
{tibp="I4"},
|
||||
{gen="H"},
|
||||
{ads="I4"},
|
||||
{fragaddr="I4"},
|
||||
{osval2="c10"}
|
||||
}
|
0
ksrc/fs/foxfs/mkfoxfs.lua
Normal file
0
ksrc/fs/foxfs/mkfoxfs.lua
Normal file
13
ksrc/fs/foxfs/superblock.lua
Normal file
13
ksrc/fs/foxfs/superblock.lua
Normal file
@ -0,0 +1,13 @@
|
||||
local superblock = struct {
|
||||
endian = "<",
|
||||
{sig="H"},
|
||||
{ver_maj="H"},
|
||||
{ver_min="H"},
|
||||
{state="H"},
|
||||
{total_inodes="I4"},
|
||||
{total_blocks="I4"},
|
||||
{reserved_blocks="I4"},
|
||||
{total_unalloc_blocks="I4"},
|
||||
{total_unalloc_inodes="I4"},
|
||||
{total_unalloc_inodes="I4"},
|
||||
}
|
38
ksrc/init.lua
Normal file
38
ksrc/init.lua
Normal file
@ -0,0 +1,38 @@
|
||||
--#include "ksrc/kstrings.lua"
|
||||
--#include "ksrc/kargs.lua"
|
||||
--#include "ksrc/kio.lua"
|
||||
--#include "ksrc/vfs.lua"
|
||||
--#include "ksrc/struct.lua"
|
||||
--#include "ksrc/string.lua"
|
||||
--#include "ksrc/archives.lua"
|
||||
--#include "ksrc/ads.lua"
|
||||
--#include "ksrc/blkdev.lua"
|
||||
--#include "ksrc/acl.lua"
|
||||
--#include "ksrc/security.lua"
|
||||
--#include "ksrc/exec.lua"
|
||||
--#include "ksrc/fs/foxfs/init.lua"
|
||||
--#include "ksrc/tty.lua"
|
||||
--#include "ksrc/biosfixes.lua"
|
||||
--#include "ksrc/buffer.lua"
|
||||
--#include "ksrc/threads.lua"
|
||||
--#include "ksrc/net.lua"
|
||||
|
||||
kio.dmesg(1, "Starting Tsuki kernel.")
|
||||
kio.init()
|
||||
|
||||
-- Mount the initramfs, if there is one.
|
||||
if (kargs.iramfs or kargs.root == "$") then
|
||||
vfs.mount("/", arcfs.proxy(_ARCHIVE))
|
||||
end
|
||||
|
||||
-- Eventually...
|
||||
do
|
||||
local pty = tty.get(0)
|
||||
kio.dmesg(1, "Passing off to init.")
|
||||
exec.startfile(kargs.init or "/bin/init.velx", true, {
|
||||
uid = 0,
|
||||
gid = 0,
|
||||
tty = pty,
|
||||
args = {kargs}
|
||||
})
|
||||
end
|
0
ksrc/kargs.lua
Normal file
0
ksrc/kargs.lua
Normal file
299
ksrc/kio.lua
Normal file
299
ksrc/kio.lua
Normal file
@ -0,0 +1,299 @@
|
||||
@[[if not svar.get("PRINT_DMESG_LEVEL") then
|
||||
svar.set("PRINT_DMESG_LEVEL", "1")
|
||||
end]]
|
||||
|
||||
---@module kio "Kernel I/O"
|
||||
kio = {}
|
||||
|
||||
local _stream = {}
|
||||
function _stream:read(amt)
|
||||
local buf = ""
|
||||
local lc = ""
|
||||
if (amt == "*l") then -- Our line ending is \n
|
||||
repeat
|
||||
lc = self.proto.read(self.udat, 1)
|
||||
if (lc ~= "\n") then
|
||||
buf = buf .. (lc or "")
|
||||
end
|
||||
until not lc or lc == "" or lc == "\n"
|
||||
return buf
|
||||
--elseif (amt == "*n") then
|
||||
|
||||
elseif (amt == "*a") then
|
||||
local pos = self:seek("cur", 0)
|
||||
local send = self:seek("end", 0)
|
||||
self:seek("set", pos)
|
||||
amt = send - pos
|
||||
end
|
||||
return self.proto.read(self.udat, amt)
|
||||
end
|
||||
|
||||
function _stream:write(data)
|
||||
return self.proto.write(self.udat, data)
|
||||
end
|
||||
|
||||
function _stream:seek(whence, amt)
|
||||
if not amt then
|
||||
amt = whence or 0
|
||||
whence = "cur"
|
||||
end
|
||||
return self.proto.seek(self.udat, whence, amt)
|
||||
end
|
||||
|
||||
function _stream:eof()
|
||||
local pos = self:seek("cur", 0)
|
||||
local send = self:seek("end", 0)
|
||||
self:seek("set", pos)
|
||||
return pos == send
|
||||
end
|
||||
|
||||
function _stream:close()
|
||||
return self.proto.close(self.udat)
|
||||
end
|
||||
|
||||
function _stream:size()
|
||||
local pos = self:seek("cur", 0)
|
||||
local send = self:seek("end", 0)
|
||||
self:seek("set", pos)
|
||||
return send
|
||||
end
|
||||
|
||||
function kio.create_stream(udat, proto)
|
||||
return setmetatable({udat=udat, proto=proto}, {__index=_stream})
|
||||
end
|
||||
|
||||
@[[local kio_errc = 0
|
||||
function kio_err(name, rtn)]]
|
||||
kio.errno["@[{name}]"] = @[{kio_errc}]
|
||||
kio_errors[@[{kio_errc}]] = "@[{rtn}]"
|
||||
@[[kio_errc = kio_errc + 1
|
||||
end]]
|
||||
|
||||
kio.errno = {}
|
||||
local kio_errors = {}
|
||||
@[[
|
||||
kio_err("FILE_NOT_FOUND", "not found")
|
||||
kio_err("FILE_DIRECTORY", "file is a directory")
|
||||
kio_err("DEV_TIMEOUT", "device timeout")
|
||||
kio_err("IO_ERROR", "generic i/o error")
|
||||
kio_err("UNSUPPORTED_OPERATION", "unsupported operation")
|
||||
kio_err("NOT_ALLOWED", "not allowed")
|
||||
kio_err("TOO_MANY_SYMLINKS", "too many symlinks")
|
||||
kio_err("DEV_FULL", "device is full")
|
||||
kio_err("DEV_READ_ONLY", "device is read only")
|
||||
]]
|
||||
|
||||
kio.geterror = function(e)
|
||||
return nil, kio_errors[e] or "generic error"
|
||||
end
|
||||
|
||||
function kio.invoke(path, method, ...)
|
||||
local dev, rpath = vfs.resolve(path)
|
||||
return dev.dev[method](dev.dev, rpath, ...)
|
||||
end
|
||||
|
||||
function kio.has_ads(path)
|
||||
|
||||
end
|
||||
|
||||
function kio.ads_exists(path, ads)
|
||||
|
||||
end
|
||||
|
||||
function kio.has_acl(path)
|
||||
|
||||
end
|
||||
|
||||
---@func calc_seek
|
||||
---@arg whence string "Like io.seek's whence."
|
||||
---@arg amt integer "The amount to seek."
|
||||
---@arg size integer "The size of the stream."
|
||||
---@arg pos integer "The current position."
|
||||
---@return integer "The new position"
|
||||
---@desc "This function calculates the new position for seeking."
|
||||
function kio.calc_seek(whence, amt, size, pos)
|
||||
if (whence == "cur") then
|
||||
pos = pos + amt
|
||||
elseif (whence == "end") then
|
||||
pos = size + amt
|
||||
elseif (whence == "set") then
|
||||
pos = amt
|
||||
end
|
||||
if pos > size then
|
||||
pos = size
|
||||
elseif pos < 1 then
|
||||
pos = 1
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
---@func filestream
|
||||
---@arg path string "Path to the file"
|
||||
---@arg mode string "File mode"
|
||||
---@return stream "The stream for the file."
|
||||
---@desc "This creates a stream from a file."
|
||||
function kio.filestream(path, mode)
|
||||
local dev, rpath = vfs.resolve(path)
|
||||
local h = dev:open(rpath, mode)
|
||||
local stat = dev:stat(rpath)
|
||||
return kio.create_stream({dev=dev, hand=h, stat=stat}, {
|
||||
read = function(self, amt)
|
||||
return self.dev:read(self.hand, amt)
|
||||
end,
|
||||
seek = function(self, whence, amt)
|
||||
local pos = self.dev:seek(self.hand, 0)
|
||||
local npos = kio.calc_seek(whence, amt, self.stat.size, pos)
|
||||
return self.dev:seek(self.hand, npos-pos)
|
||||
end,
|
||||
write = function(self, data)
|
||||
return self.dev:write(self.hand, data)
|
||||
end,
|
||||
close = function(self)
|
||||
return self.dev:close(self.hand)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
---@func dir
|
||||
---@arg udat table "The data to pass to to prototype"
|
||||
---@arg proto function "The prototype function for the iterator"
|
||||
---@return function "The iterator."
|
||||
---@desc "Creates a directory iterator."
|
||||
function kio.dir(udat, proto)
|
||||
return function()
|
||||
return proto(udat)
|
||||
end
|
||||
end
|
||||
|
||||
---@func memstream
|
||||
---@arg str string "The string to create a stream of."
|
||||
---@arg write boolean "If the stream should be writable or not."
|
||||
---@return stream "The memory stream."
|
||||
---@desc "Creates a memory stream."
|
||||
---@note "stream:close() returns the string."
|
||||
function kio.memstream(str, write)
|
||||
return kio.create_stream({str=str, pos=1, write=write}, {
|
||||
read = function(self, amt)
|
||||
local dat = self.str:sub(self.pos, self.pos+amt-1)
|
||||
self.pos = self.pos+#dat
|
||||
return dat
|
||||
end,
|
||||
write = function(self, dat)
|
||||
if (write) then
|
||||
local startstr = self.str:sub(1, self.pos-1)
|
||||
local endstr = self.str:sub(self.pos+#dat)
|
||||
self.str = startstr..dat..endstr
|
||||
self.pos = self.pos + #dat
|
||||
end
|
||||
end,
|
||||
seek = function(self, whence, amt)
|
||||
self.pos = kio.calc_seek(whence, amt, #self.str, self.pos)
|
||||
return self.pos
|
||||
end,
|
||||
close = function(self)
|
||||
return self.str
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
kio.loglevel = {
|
||||
DEBUG = 0,
|
||||
INFO = 1,
|
||||
WARNING = 2,
|
||||
ERROR = 3,
|
||||
PANIC = 255
|
||||
}
|
||||
|
||||
kio.levels = {
|
||||
[0] = "DEBUG",
|
||||
"INFO",
|
||||
"WARNING",
|
||||
"ERROR",
|
||||
[255] = "PANIC"
|
||||
}
|
||||
|
||||
---@func dprint
|
||||
---@arg level integer "The log level"
|
||||
---@arg status string "The message."
|
||||
---@desc "This method logs to the kernel log and wherever else is set up to be printed to."
|
||||
function kio.dprint(level, status)
|
||||
local stack = {}
|
||||
local lkexec = {}
|
||||
local i = 0
|
||||
while lkexec do
|
||||
lkexec = debug.getinfo(i)
|
||||
stack[#stack+1] = lkexec
|
||||
end
|
||||
local src = stack[#stack].source:sub(2)
|
||||
local spart = vfs.parts(src)
|
||||
local exec = spart[#spart]:match("^(.+)%.([^%.]+)$")
|
||||
local message = string.format("[%.2f] [%s] [%s] %s", computer.uptime(), levels[level], exec, status)
|
||||
dmesgs[#dmesgs+1] = {ut=computer.uptime,lvl=level,x=exec,st=status}
|
||||
if (level < $[{PRINT_DMESG_LEVEL}]) then
|
||||
sig.push {
|
||||
type = "dprint",
|
||||
msg = message
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
---@func dmesg
|
||||
---@see kio.dprint
|
||||
kio.dmesg = dprint
|
||||
|
||||
---@func panic
|
||||
---@arg msg string "The error message to display."
|
||||
function kio.panic(msg)
|
||||
dmesg(255, "Kernel panic!")
|
||||
end
|
||||
|
||||
---@func create_pipe
|
||||
---@return stream "Pipe in"
|
||||
---@return stream "Pipe out"
|
||||
---@desc "Creates a pipe."
|
||||
function kio.create_pipe()
|
||||
local pipecore = kio.memstream()
|
||||
local pipein = kio.create_stream({
|
||||
dat = pipecore
|
||||
}, {
|
||||
read = function()
|
||||
-- no
|
||||
end,
|
||||
seek = function()
|
||||
-- no
|
||||
end,
|
||||
write = function(self, dat)
|
||||
self.dat:seek("end", 0)
|
||||
self.dat:write(dat)
|
||||
end,
|
||||
close = function()
|
||||
-- *no*
|
||||
end
|
||||
})
|
||||
local pipeout = kio.create_stream({
|
||||
dat = pipecore,
|
||||
pos = 1
|
||||
}, {
|
||||
read = function(self, amt)
|
||||
self.dat:seek("set", self.pos)
|
||||
local dat = self.dat:read()
|
||||
self.pos = self.pos+#dat
|
||||
return dat
|
||||
end,
|
||||
seek = function()end,
|
||||
write = function()end,
|
||||
close = function()end
|
||||
})
|
||||
return pipein, pipeout
|
||||
end
|
||||
|
||||
---@func init
|
||||
---@desc "Only called once. Sets up the kio library."
|
||||
function kio.init()
|
||||
---@func create_buffer
|
||||
---@arg blocking boolean "True if read calls to a buffer that doesn't contain enough data block."
|
||||
---@arg pid integer "This is set to the PID of the process which handles the buffers."
|
||||
---@return table "The buffer for use anywhere."
|
||||
kio.create_buffer = create_buffer
|
||||
kio.init = false
|
||||
end
|
6
ksrc/kstrings.lua
Normal file
6
ksrc/kstrings.lua
Normal file
@ -0,0 +1,6 @@
|
||||
_KINFO = {
|
||||
name = "Tsuki",
|
||||
release = "$[{TSUKI_RELEASE}]",
|
||||
version = "$[{TSUKI_VERSION}]",
|
||||
machine = "$[{TSUKI_TARGET}]", -- OC or LuPI2
|
||||
}
|
0
ksrc/lupi2.lua
Normal file
0
ksrc/lupi2.lua
Normal file
6
ksrc/net.lua
Normal file
6
ksrc/net.lua
Normal file
@ -0,0 +1,6 @@
|
||||
--#include "ksrc/net/tsukinet/init.lua"
|
||||
|
||||
local net = {}
|
||||
function net.open(netinfo)
|
||||
|
||||
end
|
0
ksrc/net/tsukinet/init.lua
Normal file
0
ksrc/net/tsukinet/init.lua
Normal file
20
ksrc/security.lua
Normal file
20
ksrc/security.lua
Normal file
@ -0,0 +1,20 @@
|
||||
---@module security Security
|
||||
local security = {}
|
||||
|
||||
---@func checkacl
|
||||
---@arg permission string "The permission to check."
|
||||
---@return boolean "True if the current process has this permission."
|
||||
function security.checkacl(permission)
|
||||
local perms = acl.get("group", thread.info().egid, {})
|
||||
end
|
||||
|
||||
---@func getmode
|
||||
---@return string "The current security mode."
|
||||
function security.getmode()
|
||||
|
||||
end
|
||||
|
||||
function security.init()
|
||||
klog("security", 1, "Security init started.")
|
||||
|
||||
end
|
6
ksrc/stdlib/err.lua
Normal file
6
ksrc/stdlib/err.lua
Normal file
@ -0,0 +1,6 @@
|
||||
_P.pcall = pcall
|
||||
_P.xpcall = xpcall
|
||||
|
||||
_P.error = {}
|
||||
_P.error.geterror = kio.geterror
|
||||
_P.error.errno = kio.errno
|
10
ksrc/stdlib/init.lua
Normal file
10
ksrc/stdlib/init.lua
Normal file
@ -0,0 +1,10 @@
|
||||
function _P.load(...)
|
||||
if (security.checkacl("unsigned_code")) then
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--#include "ksrc/stdlib/err.lua"
|
||||
--#include "ksrc/stdlib/string.lua"
|
||||
--#include "ksrc/stdlib/thread.lua"
|
||||
--#include "ksrc/stdlib/err.lua"
|
0
ksrc/stdlib/io.lua
Normal file
0
ksrc/stdlib/io.lua
Normal file
11
ksrc/stdlib/string.lua
Normal file
11
ksrc/stdlib/string.lua
Normal file
@ -0,0 +1,11 @@
|
||||
_P.string = {}
|
||||
@[[function copylib(method)]]
|
||||
_P.string.@[{method}] = string.@[{method}]
|
||||
@[[end]]
|
||||
|
||||
@[[for k, v in pairs(string) do
|
||||
copylib(k)
|
||||
end]]
|
||||
@[[copylib("trim")]]
|
||||
@[[copylib("explode")]]
|
||||
@[[copylib = nil]]
|
9
ksrc/stdlib/table.lua
Normal file
9
ksrc/stdlib/table.lua
Normal file
@ -0,0 +1,9 @@
|
||||
_P.table = {}
|
||||
@[[function copylib(method)]]
|
||||
_P.table.@[{method}] = table.@[{method}]
|
||||
@[[end]]
|
||||
|
||||
@[[for k, v in pairs(table) do
|
||||
copylib(k)
|
||||
end]]
|
||||
@[[copylib = nil]]
|
9
ksrc/stdlib/thread.lua
Normal file
9
ksrc/stdlib/thread.lua
Normal file
@ -0,0 +1,9 @@
|
||||
_P.threads = {}
|
||||
|
||||
function _P.threads.add(name, func)
|
||||
|
||||
end
|
||||
|
||||
function _P.threads.load(path, args)
|
||||
|
||||
end
|
25
ksrc/string.lua
Normal file
25
ksrc/string.lua
Normal file
@ -0,0 +1,25 @@
|
||||
string.newline = "\n"
|
||||
|
||||
function string.trim(self)
|
||||
return self:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
function string.explode(self, pat)
|
||||
local t, ll
|
||||
t={}
|
||||
ll=0
|
||||
if(#p == 1) then
|
||||
return {p}
|
||||
end
|
||||
while true do
|
||||
l = string.find(self, pat, ll, true) -- find the next d in the string
|
||||
if l ~= nil then -- if "not not" found then..
|
||||
table.insert(t, string.sub(self,ll,l-1)) -- Save it in our array.
|
||||
ll = l + 1 -- save just after where we found it for searching next time.
|
||||
else
|
||||
table.insert(t, string.sub(self,ll)) -- Save what's left in our array.
|
||||
break -- Break at end, as it should be, according to the lua manual.
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
29
ksrc/struct.lua
Normal file
29
ksrc/struct.lua
Normal file
@ -0,0 +1,29 @@
|
||||
function struct(tbl)
|
||||
local pat = tbl.endian or "="
|
||||
local args = {}
|
||||
for i=1, do
|
||||
local a, b = pairs(tbl[i])
|
||||
local k, v = a(b)
|
||||
args[i] = k
|
||||
pat = pat .. v
|
||||
end
|
||||
return setmetatable({}, {__call=function(_, arg)
|
||||
checkArg(1, arg, "string", "table")
|
||||
if (type(arg) == "string") then
|
||||
local sval = {string.unpack(pat, arg)}
|
||||
local rtn = {}
|
||||
for i=1, #args do
|
||||
rtn[args[i]] = sval[i]
|
||||
end
|
||||
return rtn, sval[#sval]
|
||||
elseif (type(arg) == "table") then
|
||||
local sval = {}
|
||||
for i=1, #args do
|
||||
sval[i] = arg[args[i]]
|
||||
end
|
||||
return string.pack(pat, unpack(sval))
|
||||
end
|
||||
end, __len=function()
|
||||
return string.packsize(pat)
|
||||
end})
|
||||
end
|
56
ksrc/threads.lua
Normal file
56
ksrc/threads.lua
Normal file
@ -0,0 +1,56 @@
|
||||
local thd = {}
|
||||
local next_pause = 0
|
||||
local max_proctime = 5 -- 5s of process time max.
|
||||
local last_proctime = 0
|
||||
local lastsig = {}
|
||||
local threads = {}
|
||||
local function run_threads()
|
||||
local rthd = {}
|
||||
local mfd = {}
|
||||
for i=1, #thd do
|
||||
if (threads[i].dead) then
|
||||
mfd[#mfd+1] = i
|
||||
elseif (threads[i].deadline >= computer.uptime()) then
|
||||
rthd[#rthd+1] = threads[i]
|
||||
end
|
||||
end
|
||||
table.sort(rthd, function(a, b)
|
||||
if (a.priority == b.priority) then
|
||||
return a.deadline < b.deadline
|
||||
end
|
||||
return a.priority < b.priority
|
||||
end)
|
||||
local starttime = computer.uptime()
|
||||
local mindl = math.huge
|
||||
for i=1, #rthd do
|
||||
local ok, dl = coroutine.resume(rthd[i].coro, table.unpack(rthd[i].args or lastsig))
|
||||
if (not ok or coroutine.status(rthd[i].coro) == "dead") then
|
||||
signal.push(thd.get(rthd[i].parent), {"subproc", "dead", rthd[i].pid, (rthd[i].exitcode or (dl and 1) or 0)})
|
||||
for j=1, #thd do
|
||||
if (threads[j] == rthd[i]) then
|
||||
mfd[#mfd+1] = j
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
mindl = ((mindl > dl) and dl) or mindl
|
||||
buffers.update(rthd[i])
|
||||
if (rthd[i].sigpushed) then
|
||||
mindl = 0
|
||||
rthd[i].sigpushed = false
|
||||
end
|
||||
end
|
||||
if (computer.uptime() >= starttime+max_proctime) then
|
||||
goto cleanup
|
||||
end
|
||||
end
|
||||
::cleanup::
|
||||
for i=#mfd, 1, -1 do
|
||||
table.remove(threads, mfd[i])
|
||||
end
|
||||
lastsig = table.pack(computer.pullSignal(mindl))
|
||||
end
|
||||
|
||||
function thd.add(tinfo)
|
||||
|
||||
end
|
15
ksrc/tty.lua
Normal file
15
ksrc/tty.lua
Normal file
@ -0,0 +1,15 @@
|
||||
local tty = {}
|
||||
do
|
||||
local _tty = {}
|
||||
function _tty:getgpu()
|
||||
return self.gpu.address
|
||||
end
|
||||
|
||||
function _tty:getkb()
|
||||
return self.kb.address
|
||||
end
|
||||
|
||||
function _tty:getscreen()
|
||||
return self.screen.address
|
||||
end
|
||||
end
|
13
ksrc/vfs.lua
Normal file
13
ksrc/vfs.lua
Normal file
@ -0,0 +1,13 @@
|
||||
local vfs = {}
|
||||
|
||||
function vfs.mount(path, proxy)
|
||||
|
||||
end
|
||||
|
||||
function vfs.resolve(path)
|
||||
|
||||
end
|
||||
|
||||
function vfs.umount(pathorproxy)
|
||||
|
||||
end
|
6
readme.md
Normal file
6
readme.md
Normal file
@ -0,0 +1,6 @@
|
||||
# The Tsuki kernel
|
||||
|
||||
The Tsuki kernel is a UNIX-like kernel for OpenComputers and LuPI2.
|
||||
|
||||
## Building
|
||||
Clone the repo and run `./build.sh`.
|
260
utils/gendocs.lua
Normal file
260
utils/gendocs.lua
Normal file
@ -0,0 +1,260 @@
|
||||
local outdir = arg[1]
|
||||
|
||||
function string.trim(self)
|
||||
return self:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
local escapes = {
|
||||
["\\"] = "\\",
|
||||
["n"] = "\n",
|
||||
["t"] = "\t",
|
||||
["r"] = "\r"
|
||||
}
|
||||
local docs = {}
|
||||
local cdoc
|
||||
local cfunc
|
||||
local function parse_string(str, close, noesc)
|
||||
local s = ""
|
||||
local esc = false
|
||||
repeat
|
||||
local c = str.read()
|
||||
if not esc then
|
||||
if (c ~= "\\" or noesc) then
|
||||
s = s .. c
|
||||
else
|
||||
esc = true
|
||||
end
|
||||
else
|
||||
if (escapes[c]) then
|
||||
s = s .. escapes[c]
|
||||
else
|
||||
return nil, "invalid escape"
|
||||
end
|
||||
end
|
||||
until str.peek(#close) == close or str.peek(#close) == ""
|
||||
str.seek(#close)
|
||||
return s
|
||||
end
|
||||
|
||||
local function parse_dec(str)
|
||||
local num = ""
|
||||
repeat
|
||||
num = num .. str.read()
|
||||
until not str.peek():match("%d") or str.peek() == ""
|
||||
return tonumber(num, 10)
|
||||
end
|
||||
|
||||
local function parse_hex(str)
|
||||
if not str.peek():match("%x") then
|
||||
return nil, "malformed hex"
|
||||
end
|
||||
local num = ""
|
||||
repeat
|
||||
num = num .. str.read()
|
||||
until not str.peek():match("%x") or str.peek() == ""
|
||||
return tonumber(num, 16)
|
||||
end
|
||||
local ln = 0
|
||||
local function parse_line(line)
|
||||
local args = {}
|
||||
local idx = 1
|
||||
local str = {
|
||||
peek = function(amt)
|
||||
amt = amt or 1
|
||||
return line:sub(idx, idx+amt-1)
|
||||
end,
|
||||
read = function(amt)
|
||||
amt = amt or 1
|
||||
local data = line:sub(idx, idx+amt-1)
|
||||
idx = idx + amt
|
||||
return data
|
||||
end,
|
||||
seek = function(amt)
|
||||
amt = amt or 0
|
||||
idx = idx + amt
|
||||
return idx
|
||||
end
|
||||
}
|
||||
local function lassert(a, b)
|
||||
return assert(a, "line #"..ln..": "..(b or "unknown error"))
|
||||
end
|
||||
while str.peek() ~= "" do
|
||||
if (str.peek() == "\"") then
|
||||
str.seek(1)
|
||||
args[#args+1] = lassert(parse_string(str, "\"", false))
|
||||
elseif (str.peek(2) == "0x") then
|
||||
str.seek(2)
|
||||
args[#args+1] = lassert(parse_hex(str))
|
||||
elseif (str.peek(1):match("%d")) then
|
||||
args[#args+1] = lassert(parse_dec(str))
|
||||
elseif (str.peek() == "'") then
|
||||
str.seek(1)
|
||||
args[#args+1] = lassert(parse_string(str, "'", false))
|
||||
elseif (str.peek() == " ") then
|
||||
--do nothing
|
||||
else
|
||||
args[#args+1] = lassert(parse_string(str, " ", true))
|
||||
end
|
||||
end
|
||||
return args
|
||||
end
|
||||
local function is_comment(line)
|
||||
if (line:trim():sub(1, 2) == "--") then
|
||||
return true, line:sub(3)
|
||||
end
|
||||
end
|
||||
for line in io.stdin:lines() do
|
||||
ln = ln+1
|
||||
local com, rline = is_comment(line)
|
||||
if (com) then
|
||||
if (rline:match("^%-@module")) then
|
||||
local args = parse_line(rline:sub(10))
|
||||
if (cdoc) then
|
||||
if (cfunc) then
|
||||
cdoc.methods[#cdoc.methods+1] = cfunc
|
||||
cfunc = nil
|
||||
end
|
||||
docs[#docs+1] = cdoc
|
||||
end
|
||||
cdoc = {
|
||||
type = "module",
|
||||
methods = {},
|
||||
name = args[2],
|
||||
mod = args[1]
|
||||
}
|
||||
elseif (rline:match("^%-@section")) then
|
||||
local args = parse_line(rline:sub(11))
|
||||
if (cdoc) then
|
||||
if (cfunc) then
|
||||
cdoc.methods[#cdoc.methods+1] = cfunc
|
||||
cfunc = nil
|
||||
end
|
||||
docs[#docs+1] = cdoc
|
||||
end
|
||||
cdoc = {
|
||||
type = "generic",
|
||||
methods = {},
|
||||
name = args[2],
|
||||
mod = args[1]
|
||||
}
|
||||
elseif (rline:match("^%-@page")) then
|
||||
if (cfunc) then
|
||||
cdoc.methods[#cdoc.methods+1] = cfunc
|
||||
end
|
||||
local args = parse_line(rline:sub(8))
|
||||
cfunc = {
|
||||
type = "page",
|
||||
doc = {},
|
||||
name = args[1],
|
||||
print_name = args[2]
|
||||
}
|
||||
elseif (rline:match("^%-@arg") and cfunc.type == "func") then
|
||||
local args = parse_line(rline:sub(7))
|
||||
cfunc.args[#cfunc.args+1] = {
|
||||
name = args[1],
|
||||
type = args[2],
|
||||
doc = args[3]
|
||||
}
|
||||
elseif (rline:match("^%-@return") and cfunc.type == "func") then
|
||||
local args = parse_line(rline:sub(10))
|
||||
cfunc.ret[#cfunc.ret+1] = {
|
||||
type = args[1],
|
||||
doc = args[2],
|
||||
}
|
||||
elseif (rline:match("^%-@doc")) then
|
||||
local args = parse_line(rline:sub(7))
|
||||
cfunc.doc[#cfunc.doc+1] = {
|
||||
doc = args[1],
|
||||
}
|
||||
elseif (rline:match("^%-@see")) then
|
||||
local args = parse_line(rline:sub(7))
|
||||
cfunc.doc[#cfunc.doc+1] = {
|
||||
doc = "See \27_S"..args[1].."\27_E"
|
||||
}
|
||||
elseif (rline:match("^%-@note")) then
|
||||
local args = parse_line(rline:sub(8))
|
||||
cfunc.doc[#cfunc.doc+1] = {
|
||||
doc = "NOTE: "..args[1]
|
||||
}
|
||||
elseif (rline:match("^%-@desc")) then
|
||||
local args = parse_line(rline:sub(8))
|
||||
cfunc.doc[#cfunc.doc+1] = {
|
||||
doc = args[1]
|
||||
}
|
||||
elseif (rline:match("^%-@vararg")) then
|
||||
cfunc.vararg = true
|
||||
elseif (rline:match("^%-@varret")) then
|
||||
cfunc.varret = true
|
||||
elseif (rline:match("^%-@func")) then
|
||||
if (cfunc) then
|
||||
cdoc.methods[#cdoc.methods+1] = cfunc
|
||||
end
|
||||
local args = parse_line(rline:sub(8))
|
||||
cfunc = {
|
||||
type = "func",
|
||||
doc = {},
|
||||
name = args[1],
|
||||
ret = {},
|
||||
args = {}
|
||||
}
|
||||
end
|
||||
else
|
||||
io.stderr:write(line.."\n")
|
||||
end
|
||||
end
|
||||
|
||||
if (cfunc) then
|
||||
cdoc.methods[#cdoc.methods+1] = cfunc
|
||||
end
|
||||
if (cdoc) then
|
||||
docs[#docs+1] = cdoc
|
||||
end
|
||||
for i=1, #docs do
|
||||
os.execute("mkdir -p \""..outdir.."/"..docs[i].mod:trim().."\"")
|
||||
for j=1, #docs[i].methods do
|
||||
local docc = ""
|
||||
local f = io.open(outdir.."/"..docs[i].mod:trim().."/"..docs[i].methods[j].name:trim()..".tdf", "wb")
|
||||
if (docs[i].methods[j].type == "func") then
|
||||
local argtext = ""
|
||||
local fun = docs[i].mod.."."..docs[i].methods[j].name.."("
|
||||
if (#docs[i].methods[j].args > 0) then
|
||||
for k=1, #docs[i].methods[j].args do
|
||||
fun = fun .. docs[i].methods[j].args[k].name..":"..docs[i].methods[j].args[k].type .. ", "
|
||||
argtext = argtext .. docs[i].methods[j].args[k].name .. " - " .. docs[i].methods[j].args[k].doc .. "\n"
|
||||
end
|
||||
if (docs[i].methods[j].vararg) then
|
||||
fun = fun .. "..."
|
||||
else
|
||||
fun = fun:sub(1, #fun-2)
|
||||
end
|
||||
else
|
||||
argtext = "No arguments"
|
||||
end
|
||||
fun = fun .. ")"
|
||||
|
||||
local rettext = ""
|
||||
if (#docs[i].methods[j].ret > 0) then
|
||||
fun = fun .. ":"
|
||||
for k=1, #docs[i].methods[j].ret do
|
||||
fun = fun .. docs[i].methods[j].ret[k].type .. ", "
|
||||
rettext = rettext .. docs[i].methods[j].ret[k].type .. " - " .. docs[i].methods[j].ret[k].doc .. "\n"
|
||||
end
|
||||
if (docs[i].methods[j].varret) then
|
||||
fun = fun .. "..."
|
||||
else
|
||||
fun = fun:sub(1, #fun-2)
|
||||
end
|
||||
else
|
||||
rettext = "No return."
|
||||
end
|
||||
docc = docc .. fun .. "\n\nArguments:\n"..argtext.."\n\nReturns:\n"..rettext.."\n\n"
|
||||
else
|
||||
docc = docc .. docs[i].methods[j].print_name .. "\n\n"
|
||||
end
|
||||
for k=1, #docs[i].methods[j].doc do
|
||||
docc = docc..docs[i].methods[j].doc[k].doc .. "\n"
|
||||
end
|
||||
f:write(docc)
|
||||
f:close()
|
||||
end
|
||||
end
|
64
utils/mkvelx.lua
Normal file
64
utils/mkvelx.lua
Normal file
@ -0,0 +1,64 @@
|
||||
local f = io.popen("luacomp "..arg[1], "r")
|
||||
local prog = f:read("*a")
|
||||
f:close()
|
||||
|
||||
local function struct(tbl)
|
||||
local pat = tbl.endian or "="
|
||||
local args = {}
|
||||
for i=1, #tbl do
|
||||
local a, b = pairs(tbl[i])
|
||||
local k, v = a(b)
|
||||
args[i] = k
|
||||
pat = pat .. v
|
||||
end
|
||||
return setmetatable({}, {__call=function(_, arg)
|
||||
--checkArg(1, arg, "string", "table")
|
||||
if (type(arg) == "string") then
|
||||
local sval = {string.unpack(pat, arg)}
|
||||
local rtn = {}
|
||||
for i=1, #args do
|
||||
rtn[args[i]] = sval[i]
|
||||
end
|
||||
return rtn, sval[#sval]
|
||||
elseif (type(arg) == "table") then
|
||||
local sval = {}
|
||||
for i=1, #args do
|
||||
sval[i] = arg[args[i]]
|
||||
end
|
||||
return string.pack(pat, unpack(sval))
|
||||
end
|
||||
end, __len=function()
|
||||
return string.packsize(pat)
|
||||
end})
|
||||
end
|
||||
|
||||
|
||||
local velx_spec = struct {
|
||||
endian = "<",
|
||||
{magic="c5"},
|
||||
{fver="B"},
|
||||
{compression="B"},
|
||||
{lver="B"},
|
||||
{os="B"},
|
||||
{arctype="c4"},
|
||||
{psize="I3"},
|
||||
{lsize="I3"},
|
||||
{ssize="I3"},
|
||||
{rsize="I4"}
|
||||
}
|
||||
|
||||
f = io.open(arg[2], "wb")
|
||||
f:write(velx_spec({
|
||||
magic="\27VelX",
|
||||
fver=1,
|
||||
compression=0,
|
||||
lver=0x53,
|
||||
os=127,
|
||||
arctype="",
|
||||
psize=#prog,
|
||||
lsize=0,
|
||||
ssize=0,
|
||||
rsize=0,
|
||||
}))
|
||||
f:write(prog)
|
||||
f:close()
|
207
utils/velxdump.lua
Normal file
207
utils/velxdump.lua
Normal file
@ -0,0 +1,207 @@
|
||||
--[[----------------------------------------------------------------------------
|
||||
LZSS - encoder / decoder
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
--]]----------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
local M = {}
|
||||
local string, table = string, table
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local POS_BITS = 12
|
||||
local LEN_BITS = 16 - POS_BITS
|
||||
local POS_SIZE = 1 << POS_BITS
|
||||
local LEN_SIZE = 1 << LEN_BITS
|
||||
local LEN_MIN = 3
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function M.compress(input)
|
||||
local offset, output = 1, {}
|
||||
local window = ''
|
||||
|
||||
local function search()
|
||||
for i = LEN_SIZE + LEN_MIN - 1, LEN_MIN, -1 do
|
||||
local str = string.sub(input, offset, offset + i - 1)
|
||||
local pos = string.find(window, str, 1, true)
|
||||
if pos then
|
||||
return pos, str
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while offset <= #input do
|
||||
local flags, buffer = 0, {}
|
||||
|
||||
for i = 0, 7 do
|
||||
if offset <= #input then
|
||||
local pos, str = search()
|
||||
if pos and #str >= LEN_MIN then
|
||||
local tmp = ((pos - 1) << LEN_BITS) | (#str - LEN_MIN)
|
||||
buffer[#buffer + 1] = string.pack('>I2', tmp)
|
||||
else
|
||||
flags = flags | (1 << i)
|
||||
str = string.sub(input, offset, offset)
|
||||
buffer[#buffer + 1] = str
|
||||
end
|
||||
window = string.sub(window .. str, -POS_SIZE)
|
||||
offset = offset + #str
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if #buffer > 0 then
|
||||
output[#output + 1] = string.char(flags)
|
||||
output[#output + 1] = table.concat(buffer)
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(output)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function M.decompress(input)
|
||||
local offset, output = 1, {}
|
||||
local window = ''
|
||||
|
||||
while offset <= #input do
|
||||
local flags = string.byte(input, offset)
|
||||
offset = offset + 1
|
||||
|
||||
for i = 1, 8 do
|
||||
local str = nil
|
||||
if (flags & 1) ~= 0 then
|
||||
if offset <= #input then
|
||||
str = string.sub(input, offset, offset)
|
||||
offset = offset + 1
|
||||
end
|
||||
else
|
||||
if offset + 1 <= #input then
|
||||
local tmp = string.unpack('>I2', input, offset)
|
||||
offset = offset + 2
|
||||
local pos = (tmp >> LEN_BITS) + 1
|
||||
local len = (tmp & (LEN_SIZE - 1)) + LEN_MIN
|
||||
str = string.sub(window, pos, pos + len - 1)
|
||||
end
|
||||
end
|
||||
flags = flags >> 1
|
||||
if str then
|
||||
output[#output + 1] = str
|
||||
window = string.sub(window .. str, -POS_SIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(output)
|
||||
end
|
||||
|
||||
|
||||
local function struct(tbl)
|
||||
local pat = tbl.endian or "="
|
||||
local args = {}
|
||||
for i=1, #tbl do
|
||||
local a, b = pairs(tbl[i])
|
||||
local k, v = a(b)
|
||||
args[i] = k
|
||||
pat = pat .. v
|
||||
end
|
||||
return setmetatable({}, {__call=function(_, arg)
|
||||
--checkArg(1, arg, "string", "table")
|
||||
if (type(arg) == "string") then
|
||||
local sval = {string.unpack(pat, arg)}
|
||||
local rtn = {}
|
||||
for i=1, #args do
|
||||
rtn[args[i]] = sval[i]
|
||||
end
|
||||
return rtn, sval[#sval]
|
||||
elseif (type(arg) == "table") then
|
||||
local sval = {}
|
||||
for i=1, #args do
|
||||
sval[i] = arg[args[i]]
|
||||
end
|
||||
return string.pack(pat, unpack(sval))
|
||||
end
|
||||
end, __len=function()
|
||||
return string.packsize(pat)
|
||||
end})
|
||||
end
|
||||
|
||||
local velx_spec = struct {
|
||||
endian = "<",
|
||||
{magic="c5"},
|
||||
{fver="B"},
|
||||
{compression="B"},
|
||||
{lver="B"},
|
||||
{os="B"},
|
||||
{arctype="c4"},
|
||||
{psize="I3"},
|
||||
{lsize="I3"},
|
||||
{ssize="I3"},
|
||||
{rsize="I4"}
|
||||
}
|
||||
|
||||
local compression = {
|
||||
[0] = "None",
|
||||
[1] = "LZSS"
|
||||
}
|
||||
|
||||
local os = {
|
||||
[0] = "Tsuki",
|
||||
[0x7F] = "BIOS",
|
||||
}
|
||||
|
||||
local commands = {
|
||||
["cpio"] = "cpio -t",
|
||||
["tar"] = "tar -t",
|
||||
["tsar"] = "tsar -t",
|
||||
["zip"] = "jar -t"
|
||||
}
|
||||
|
||||
local f = io.open(arg[1], "rb")
|
||||
local header = velx_spec(f:read(#velx_spec))
|
||||
local program = f:read(header.psize)
|
||||
local linker = f:read(header.lsize)
|
||||
local sigs = f:read(header.ssize)
|
||||
local archive = f:read(header.rsize)
|
||||
local lver = string.format("%x", header.lver)
|
||||
lver = lver:sub(1,1).."."..lver:sub(2,2)
|
||||
io.stdout:write(string.format([[File Version: %d
|
||||
Compression: %s
|
||||
Type: %s
|
||||
OS: %s
|
||||
Lua Version: %s
|
||||
Archive type: %s]],
|
||||
header.fver,
|
||||
compression[header.compression] or "Unknown",
|
||||
(((header.os & 0x80) > 0) and "Library") or "Executable",
|
||||
os[header.os & 0x7F] or "Unknown",
|
||||
lver,
|
||||
header.arctype:gsub("\0", "")),"\n")
|
||||
if (header.arctype ~= "\0\0\0\0" and archive ~= "") then
|
||||
local h = io.popen(commands[header.arctype:gsub("\0", "")], "w")
|
||||
h:write(archive)
|
||||
h:close()
|
||||
end
|
||||
if (header.compression == 1) then
|
||||
io.stderr:write(M.decompress(program))
|
||||
elseif (header.compression == 0) then
|
||||
io.stderr:write(program)
|
||||
end
|
Loading…
Reference in New Issue
Block a user