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