vfs rewrite lol fml

This commit is contained in:
2026-01-29 20:29:06 -05:00
parent 9bd9cdaba4
commit 1c3d2c8b48
25 changed files with 980 additions and 633 deletions

View File

@@ -70,6 +70,9 @@ while true do
print("Terminated") print("Terminated")
printInline("> ") printInline("> ")
stopInput=false stopInput=false
elseif event[1]=="keyTyped" and event[3]=="^d" then
syscall.HPV_kill(proc)
syscall.HPV_exit(0)
else else
syscall.IO_pushEvent("bash:"..tostring(pid), table.unpack(event)) syscall.IO_pushEvent("bash:"..tostring(pid), table.unpack(event))
end end

View File

@@ -1,6 +1,6 @@
local userhost = (syscall.OS_getUser() or "Unknown").."@"..(syscall.OS_getHostname() or "Unknown") local userhost = (syscall.OS_getUser() or "Unknown").."@"..(syscall.OS_getHostname() or "Unknown")
print(".. *. .. | "..userhost) print(".. *. .. | "..userhost)
print(" *= +@* +* | "..string.rep("-",#userhost)) print(" *= +@* +* | "../rep("-",#userhost))
print(" .@#. -@@@= :#@. | OS: "..(syscall.OS_version() or "Unknown")) print(" .@#. -@@@= :#@. | OS: "..(syscall.OS_version() or "Unknown"))
print(" =@@+ *@@@# +@@= | Host: "..(syscall.OS_getHost() or "Unknown")) print(" =@@+ *@@@# +@@= | Host: "..(syscall.OS_getHost() or "Unknown"))
print(" %@@%: *@@@# -%@@% | Uptime: "..(syscall.OS_getUptime() or "Unknown")) print(" %@@%: *@@@# -%@@% | Uptime: "..(syscall.OS_getUptime() or "Unknown"))

View File

View File

@@ -1,3 +1,4 @@
--:Minify:--
-- blake2s.lua -- blake2s.lua
-- Pure Lua 5.2, 32-bit only, supports keyed hashing -- Pure Lua 5.2, 32-bit only, supports keyed hashing

View File

@@ -1,33 +1,33 @@
--:Minify:-- --:Minify:--
local fs={} local fs={}
-- "VFS_open" : open -- "open" : open
-- "VFS_read" : read -- "read" : read
-- "VFS_write" : write -- "write" : write
-- "VFS_close" : close -- "close" : close
function fs.open(path, mode) function fs.open(path, mode)
local fd=syscall.VFS_open(path,mode) local fd=syscall.open(path,mode)
local ret={ local ret={
close=function() close=function()
-- close file -- close file
return syscall.VFS_close(fd) return syscall.close(fd)
end, end,
flush=function() flush=function()
-- close and reopen file to flush buffers -- close and reopen file to flush buffers
syscall.VFS_close(fd) syscall.close(fd)
fd=syscall.VFS_open(path,mode) fd=syscall.open(path,mode)
end end
} }
if mode=="r" then if mode=="r" then
ret.read=function(count) ret.read=function(count)
local data = syscall.VFS_read(fd,count) local data = syscall.read(fd,count)
return data return data
end end
ret.readAll=function(chunkSize) ret.readAll=function(chunkSize)
local chunks={} -- to store read chunks local chunks={} -- to store read chunks
while true do while true do
local chunk=syscall.VFS_read(fd,chunkSize or 65536) local chunk=syscall.read(fd,chunkSize or 65536)
if chunk==nil or #chunk==0 then break end if chunk==nil or #chunk==0 then break end
table.insert(chunks,chunk) table.insert(chunks,chunk)
end end
@@ -60,7 +60,7 @@ function fs.open(path, mode)
end end
-- Read the next chunk -- Read the next chunk
local chunk = syscall.VFS_read(fd, chunk_size) local chunk = syscall.read(fd, chunk_size)
if not chunk or chunk == "" then if not chunk or chunk == "" then
eof = true eof = true
else else
@@ -71,12 +71,12 @@ function fs.open(path, mode)
elseif mode=="w" then elseif mode=="w" then
ret.write=function(data) ret.write=function(data)
-- write data to file -- write data to file
return syscall.VFS_write(fd,data) return syscall.write(fd,data)
end end
elseif mode=="a" then elseif mode=="a" then
ret.write=function(data) ret.write=function(data)
-- append data to file -- append data to file
return syscall.VFS_write(fd,data) return syscall.write(fd,data)
end end
else else
error("Invalid mode '"..mode.."'",2) error("Invalid mode '"..mode.."'",2)
@@ -106,39 +106,39 @@ function fs.appendAllText(path, data)
end end
function fs.mkdir(path) function fs.mkdir(path)
return syscall.VFS_mkdir(path) return syscall.mkdir(path)
end end
function fs.remove(path) function fs.remove(path)
return syscall.VFS_remove(path) return syscall.remove(path)
end end
function fs.list(path) function fs.list(path)
return syscall.VFS_list(path) return syscall.list(path)
end end
function fs.type(path) function fs.type(path)
return syscall.VFS_type(path) return syscall.type(path)
end end
function fs.attributes(path) function fs.attributes(path)
return syscall.VFS_attributes(path) return syscall.attributes(path)
end end
function fs.exists(path) function fs.exists(path)
return syscall.VFS_exists(path) return syscall.exists(path)
end end
function fs.getcwd() function fs.getcwd()
return syscall.VFS_getcwd() return syscall.getcwd()
end end
function fs.setcwd(path) function fs.setcwd(path)
return syscall.VFS_setcwd(path) return syscall.setcwd(path)
end end
function fs.isDir(path) function fs.isDir(path)
return syscall.VFS_isDirectory(path) return syscall.isDirectory(path)
end end
return fs return fs

View File

@@ -6,7 +6,7 @@ syscall.IO_bind("raw")
for i,v in pairs(kernel.processes) do for i,v in pairs(kernel.processes) do
kernel.log("Spawning kernel task "..i) kernel.log("Spawning kernel task "..i)
syscall.HPV_spawn(function() syscall.spawn(function()
local status, err = pcall(v) local status, err = pcall(v)
if not status then if not status then
kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR") kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR")

View File

@@ -13,11 +13,6 @@ local function write(text)
if c == "\n" then if c == "\n" then
y = y + 1 y = y + 1
x = 1 x = 1
if y-1 >= h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
elseif c == "\t" then elseif c == "\t" then
local tabSize = 4 local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize) local spaces = tabSize - ((x - 1) % tabSize)

View File

@@ -116,14 +116,12 @@ local function write(text, term)
end end
end end
-- Handle wrapping if we go past right edge
if x > w then if x > w then
x = 1 x = 1
y = y + 1 y = y + 1
end end
-- Handle scrolling if we go past bottom if y-1 >= h then
if y-1 > h then
term.scroll(1) term.scroll(1)
y = h y = h
term.setCursorPos(x, y) term.setCursorPos(x, y)
@@ -175,8 +173,10 @@ for _, name in ipairs(getNames()) do
local t = getType(name) local t = getType(name)
if t == "monitor" then if t == "monitor" then
local monitorTerm = wrapPeripheral(name) local monitorTerm = wrapPeripheral(name)
if not monitorTerm then
error("Failed to wrap monitor peripheral")
end
monitorTerm.setTextScale(0.5) monitorTerm.setTextScale(0.5)
kernel.tty.register(name, newTTY(monitorTerm)) kernel.tty.register(name, newTTY(monitorTerm))
end end
end end

View File

@@ -1,2 +1 @@
U $;/ U $;/
U devfs0000;/dev/

View File

@@ -233,19 +233,21 @@ function kernel.reboot()
kernel.computer:reboot() kernel.computer:reboot()
end end
kernel.syscalls["OS_time"]=function() return kernel.computer:time() end kernel.syscalls["time"]=function() return kernel.computer:time() end
kernel.syscalls["OS_log"]=kernel.log kernel.syscalls["log"]=kernel.log
kernel.syscalls["OS_getUptime"]=function() return kernel.computer:clock() end kernel.syscalls["getUptime"]=function() return kernel.computer:clock() end
kernel.syscalls["OS_getUser"]=function() return kernel.user end kernel.syscalls["getUser"]=function() return kernel.user end
kernel.syscalls["OS_getHostname"]=function() return kernel.host end kernel.syscalls["getHostname"]=function() return kernel.host end
kernel.syscalls["OS_getHost"]=function() return kernel.apis._HOST end kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
kernel.syscalls["OS_version"]=function() return kernel.version end kernel.syscalls["version"]=function() return kernel.version end
kernel.syscalls["OS_setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
kernel.syscalls["OS_setUser"]=function(uid) if kernel.uid~=0 then error("Permission denied") end kernel.currentTask.uid=uid end kernel.syscalls["setUser"]=function(uid) if kernel.uid~=0 then error("Permission denied") end kernel.currentTask.uid=uid end
kernel.syscalls["test"]=function() return true end
kernel.log("Running modules") kernel.log("Running modules")
for _,p in ipairs(modules) do for _,p in ipairs(modules) do
for _,v in ipairs(p) do for _,v in ipairs(p) do
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG") end
local code=ifs.readAllText(v) local code=ifs.readAllText(v)
if not code then if not code then
kernel.log("ModuReadErr: "..v, "WARN", 8) kernel.log("ModuReadErr: "..v, "WARN", 8)
@@ -255,6 +257,7 @@ for _,p in ipairs(modules) do
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
local status, err = xpcall(func,debug.traceback, kernel) local status, err = xpcall(func,debug.traceback, kernel)
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG") end
::skip:: ::skip::
end end
end end

View File

@@ -1,11 +1,14 @@
--:Minify:--
local kernel = ... local kernel = ...
local vfs = {} local vfs = {}
kernel.vfs=vfs
vfs.mounts = { ["$"] = "/" } vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks vfs.disks = kernel.disks
-- Path handling -- Path normalization
local function normalizePath(path) local function normalizePath(path)
local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then path = cwd .. "/" .. path end
local parts = {} local parts = {}
for part in path:gmatch("[^/]+") do for part in path:gmatch("[^/]+") do
if part == ".." then if part == ".." then
@@ -17,14 +20,8 @@ local function normalizePath(path)
return "/" .. table.concat(parts, "/") .. (path:sub(-1) == "/" and "/" or "") return "/" .. table.concat(parts, "/") .. (path:sub(-1) == "/" and "/" or "")
end end
-- Resolve mount and disk path
local function resolvePath(path) local function resolvePath(path)
local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then
path = cwd .. path
end
path = normalizePath(path) path = normalizePath(path)
local mountPoint = "/" local mountPoint = "/"
@@ -36,246 +33,429 @@ local function resolvePath(path)
end end
end end
local diskPath = path:sub(#mountPoint + 1) local diskPath = path:sub(#mountPoint)
return disks[mountId], diskPath if diskPath == "" then diskPath = "/" end
return vfs.disks[mountId], diskPath
end end
-- File object creation -- Allocate file descriptor for current task
local function newFileObject(disk, handle, mode, path) local function allocFD(task)
local fd = 0
while task.fd[fd] do fd = fd + 1 end
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
return fd
end
-- System-wide open file limit
local total = 0
local function checkSystemLimit()
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
end
-- File object constructor
local function newFileObj(handle, mode, path, meta)
return { return {
disk = disk,
handle = handle, handle = handle,
mode = mode, mode = mode,
path = path, path = path,
refcount = 1 meta = meta
} }
end end
local function allocFD(task) -- Validate mode
local fd = 0 local function ismode(mode)
while task.fd[fd] do fd = fd + 1 end if not (mode == "r" or mode == "w" or mode == "a") then error("EINVAL") end
return fd
end end
local function allocFD(task) -- Parse metafile
local count = 0 local function parseMetafile(file)
for _ in pairs(task.fd) do count = count + 1 end local ret={}
if count >= kernel.config.maxFilesPerTask then local pointer=1
error("EMFILE") while pointer <= #file do
local namelen = file:byte(pointer)
pointer = pointer + 1
local name = file:sub(pointer, pointer + namelen - 1)
pointer = pointer + namelen
local owner = file:byte(pointer)
local group = file:byte(pointer+1)
local perms = file:byte(pointer+2)
pointer = pointer + 3
local cmetalen = file:byte(pointer)
pointer = pointer + 1
local cmeta = ""
if cmetalen > 0 then
cmeta = file:sub(pointer, pointer + cmetalen - 1)
pointer = pointer + cmetalen
end
ret[name] = {
owner = owner,
group = group,
perms = perms,
cmeta = cmeta
}
end
return ret
end
-- Build metafile
local function makeMetafile(meta)
local file=""
for name, m in pairs(meta) do
local entry = ""
entry = entry .. string.char(#name) .. name
entry = entry .. string.char(m.owner, m.group, m.perms)
entry = entry .. string.char(#m.cmeta) .. m.cmeta
file = file .. entry
end
return file
end
-- Get metafile path and target
local function getMeta(path)
local disk, newPath = resolvePath(path)
kernel.log(newPath)
while newPath ~= "/" and newPath~="" do
local target = newPath:match("([^/]+)/?$")
kernel.log(target)
if target == ".meta" then error("Cannot open metafile") end
if disk:fileExists(newPath .. ".meta") then
return newPath .. ".meta", target
end
newPath = newPath:gsub("/[^/]+/?$", "")
kernel.log(newPath)
kernel.saveLog()
end end
local fd = 0 return nil
while task.fd[fd] do fd = fd + 1 end
return fd
end end
local total=0 -- Get file metadata object
local function checkSystemLimit() local function getFileMeta(path)
if total >= kernel.config.maxOpenFiles-16 then local mpath, target = getMeta(path)
error("ENFILE") if not mpath then
return { owner=0, group=0, perms=62, cmeta="" }
end end
local disk, _ = resolvePath(mpath)
local file = disk:open(mpath, "r")
local text = file.read(65535)
file.close()
return parseMetafile(text)[target]
end end
-- VFS syscalls -- Permission checking
local function checkperms(meta, mode)
local modes = {
r = {owner=5, group=3, everyone=1},
w = {owner=4, group=2, everyone=0},
a = {owner=4, group=2, everyone=0}
}
local bits = meta.perms
local function bit_is_set(num, bit)
return math.floor(num / (2^bit)) % 2 == 1
end
if kernel.uid == 0 then return true end
if kernel.uid == meta.owner and bit_is_set(bits, modes[mode].owner) then return true end
if meta.group and kernel.groups then
for _, gid in ipairs(kernel.groups) do
if gid == meta.group and bit_is_set(bits, modes[mode].group) then return true end
end
end
if bit_is_set(bits, modes[mode].everyone) then return true end
error("EACCES")
end
-- mounts
local function normalizeMountPoint(path)
path = normalizePath(path)
if path ~= "/" and path:sub(-1) == "/" then
path = path:sub(1, -2)
end
return path
end
function vfs.mount(target, diskOrId)
if kernel.uid ~= 0 then error("EPERM") end
if not target then error("EINVAL") end
target = normalizeMountPoint(target)
local disk
local id
if type(diskOrId) == "string" then
disk = kernel.disks[diskOrId]
id = diskOrId
if not disk then error("ENODEV") end
elseif type(diskOrId) == "table" then
disk = diskOrId
id = tostring(disk)
vfs.disks[id] = disk
else
error("EINVAL")
end
-- Prevent shadowing an existing mount
for _, mp in pairs(vfs.mounts) do
if mp == target then
error("EBUSY")
end
end
vfs.mounts[id] = target
return true
end
function vfs.umount(target)
if kernel.uid ~= 0 then error("EPERM") end
if not target then error("EINVAL") end
target = normalizeMountPoint(target)
for id, mp in pairs(vfs.mounts) do
if mp == target then
if id == "$" then error("EBUSY") end -- root fs
vfs.mounts[id] = nil
return true
end
end
error("EINVAL")
end
-- Open file
function vfs.open(path, mode) function vfs.open(path, mode)
local task = kernel.currentTask ismode(mode)
-- check limits
checkSystemLimit() checkSystemLimit()
local task = kernel.currentTask
local fd = allocFD(task)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
if not disk then if not disk then error("NODISK") end
error("No disk mounted for path '"..path.."'")
end local meta = getFileMeta(path)
checkperms(meta, mode)
local handle = disk:open(diskPath, mode) local handle = disk:open(diskPath, mode)
if not handle then return nil end task.fd[fd] = newFileObj(handle, mode, path, meta)
total = total + 1
local file = newFileObject(disk.address, handle, mode, path)
local fd = allocFD(task)
task.fd[fd] = file
total=total+1
return fd return fd
end end
-- Read
function vfs.read(fd, count)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if file.mode ~= "r" then error("EBADF") end
return file.handle.read(count or 1)
end
-- Write
function vfs.write(fd, content)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
return file.handle.write(content)
end
-- Pread / Pwrite
function vfs.pread(fd, count, offset)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if file.mode ~= "r" then error("EBADF") end
file.handle.seek("set", offset)
return file.handle.read(count or 1)
end
function vfs.pwrite(fd, content, offset)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
file.handle.seek("set", offset)
return file.handle.write(content)
end
-- Seek
function vfs.lseek(fd, offset, whence)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
return file.handle.seek(whence or "set", offset)
end
-- Fsync
function vfs.fsync(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
file.handle.flush()
end
-- Close
function vfs.close(fd) function vfs.close(fd)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
task.fd[fd] = nil
file.refcount = file.refcount - 1
if file.refcount == 0 then
file.handle.close() file.handle.close()
end task.fd[fd] = nil
total=total-1 total = total - 1
return true
end end
function vfs.read(fd, count) -- Sendfile
local file = kernel.currentTask.fd[fd] function vfs.sendfile(outfd, infd, count)
local task = kernel.currentTask
local inFile = task.fd[infd]
local outFile = task.fd[outfd]
if not inFile or not outFile then error("EBADF") end
if inFile.mode ~= "r" then error("EBADF") end
if outFile.mode ~= "w" and outFile.mode ~= "a" then error("EBADF") end
local data = inFile.handle.read(count or 1024)
return outFile.handle.write(data)
end
-- Stat / Fstat
function vfs.stat(path)
local disk, diskPath = resolvePath(path)
local meta = getFileMeta(path)
local attrs = disk:attributes(diskPath)
return {
size = attrs.size,
modified = attrs.modified,
created = attrs.created,
owner = meta.owner,
group = meta.group,
xattr = meta.cmeta
}
end
function vfs.fstat(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.mode:find("r") then error("File not open for reading") end local disk, path = resolvePath(file.path)
return file.handle.read(count) local attrs = disk:attributes(path)
return {
size = attrs.size,
modified = attrs.modified,
created = attrs.created,
owner = file.meta.owner,
group = file.meta.group,
xattr = file.meta.cmeta
}
end end
function vfs.write(fd, data) -- Directory operations
local file = kernel.currentTask.fd[fd] function vfs.listdir(path)
if not file then error("EBADF") end local disk, diskPath = resolvePath(path)
if not file.mode:find("w") then error("File not open for writing") end if disk:type(diskPath) ~= "directory" then error("ENOTDIR") end
return file.handle.write(data) local meta = getFileMeta(path)
checkperms(meta, "r")
return disk:list(diskPath)
end end
function vfs.whereis(fd)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
return file.path
end
-- Filesystem operations
function vfs.mkdir(path) function vfs.mkdir(path)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end local meta = getFileMeta(path)
return disk:makeDirectory(diskPath) checkperms(meta, "w")
disk:makeDirectory(diskPath)
end end
function vfs.remove(path) function vfs.remove(path)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end local meta = getFileMeta(path)
return disk:remove(diskPath) checkperms(meta, "w")
disk:remove(diskPath)
end end
function vfs.attributes(path) -- Permission functions
if type(path) == "number" then function vfs.chmod(path, perms)
local file = kernel.currentTask.fd[path] local disk, diskPath = resolvePath(path)
if not file then error("EBADF") end local meta = getFileMeta(path)
return disks[file.disk]:attributes(file.path) checkperms(meta, "w")
meta.perms = perms
local mpath, target = getMeta(path)
if mpath then
local mf = disk:open(mpath,"r")
local text = mf.read(65535)
mf.close()
local parsed = parseMetafile(text)
parsed[target] = meta
local file = disk:open(mpath,"w")
file.write(makeMetafile(parsed))
file.close()
end end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:attributes(diskPath)
end end
function vfs.list(path) function vfs.fchmod(fd, perms)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
vfs.chmod(file.path, perms)
end
function vfs.chown(path, uid, gid)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end local meta = getFileMeta(path)
return disk:list(diskPath) checkperms(meta, "w")
meta.owner = uid
meta.group = gid
local mpath, target = getMeta(path)
if mpath then
local mf = disk:open(mpath,"r")
local text = mf.read(65535)
mf.close()
local parsed = parseMetafile(text)
parsed[target] = meta
local file = disk:open(mpath,"w")
file.write(makeMetafile(parsed))
file.close()
end
end
function vfs.fchown(fd, uid, gid)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
vfs.chown(file.path, uid, gid)
end end
function vfs.exists(path) function vfs.exists(path)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
if not disk then return false end local meta = getFileMeta(path)
return disk:directoryExists(diskPath) or disk:fileExists(diskPath) checkperms(meta, "r")
disk:fileExists(diskPath)
end end
function vfs.type(path) -- Export syscalls
if type(path) == "number" then local sys = kernel.syscalls
local file = kernel.currentTask.fd[path] sys["open"] = vfs.open
if not file then error("EBADF") end sys["close"] = vfs.close
return disks[file.disk]:type(file.path) sys["read"] = vfs.read
end sys["write"] = vfs.write
local disk, diskPath = resolvePath(path) sys["pread"] = vfs.pread
if not disk then error("No disk mounted") end sys["pwrite"] = vfs.pwrite
return disk:type(diskPath) sys["lseek"] = vfs.lseek
end sys["fsync"] = vfs.fsync
sys["sendfile"] = vfs.sendfile
function vfs.isDirectory(path) sys["stat"] = vfs.stat
local disk, diskPath = resolvePath(path) sys["fstat"] = vfs.fstat
if not disk then return false end sys["mkdir"] = vfs.mkdir
return disk:directoryExists(diskPath) sys["remove"] = vfs.remove
end sys["listdir"] = vfs.listdir
sys["chmod"] = vfs.chmod
-- CWD sys["fchmod"] = vfs.fchmod
function vfs.getcwd() sys["chown"] = vfs.chown
return kernel.currentTask.cwd sys["fchown"] = vfs.fchown
end sys["exists"]=vfs.exists
sys["mount"] = vfs.mount
function vfs.setcwd(path) sys["umount"] = vfs.umount
if path:sub(-1) ~= "/" then path = path .. "/" end
if path:sub(1,1) ~= "/" then path = "/" .. path end
kernel.currentTask.cwd = normalizePath(path)
end
-- Mounting
function vfs.mount(diskId, path)
if kernel.uid ~= 0 then error("Permission denied") end
if not disks[diskId] then error("Unknown disk '"..diskId.."'") end
if path:sub(-1) ~= "/" then path = path .. "/" end
for _,v in pairs(vfs.mounts) do
if v == path then error("Mount point already used") end
end
vfs.mounts[diskId] = path
end
function vfs.unmount(path)
if kernel.uid ~= 0 then error("Permission denied") end
for k,v in pairs(vfs.mounts) do
if v == path then
vfs.mounts[k] = nil
return true
end
end
return false
end
function vfs.getMounts()
return vfs.mounts
end
function vfs.virtdisk(obj)
kernel.disks[obj.address] = obj
kernel.log("Registered virtual disk at "..obj.address)
end
-- Redirect file operations to VFS
function vfs.dup(oldfd)
local task = kernel.currentTask
local file = task.fd[oldfd]
if not file then error("EBADF") end
local newfd = allocFD(task)
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
function vfs.dup2(oldfd, newfd)
local task = kernel.currentTask
local file = task.fd[oldfd]
if not file then error("EBADF") end
if oldfd == newfd then return newfd end
if task.fd[newfd] then
vfs.close(newfd)
end
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
-- Syscall registration
kernel.vfs = vfs
kernel.syscalls["VFS_open"] = vfs.open
kernel.syscalls["VFS_read"] = vfs.read
kernel.syscalls["VFS_write"] = vfs.write
kernel.syscalls["VFS_close"] = vfs.close
kernel.syscalls["VFS_list"] = vfs.list
kernel.syscalls["VFS_type"] = vfs.type
kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.syscalls["VFS_remove"] = vfs.remove
kernel.syscalls["VFS_exists"] = vfs.exists
kernel.syscalls["VFS_mount"] = vfs.mount
kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.syscalls["VFS_isDirectory"]= vfs.isDirectory
kernel.log("VFS module loaded") kernel.log("VFS module loaded")
return vfs

View File

@@ -1,7 +1,7 @@
--:Minify:-- --:Minify:--
local kernel = ... local kernel = ...
local cache = {} local cache = {}
local searchpaths = { kernel.searchpaths = {
"/lib/?.lua", "/lib/?.lua",
"/lib/?", "/lib/?",
"/usr/lib/?.lua", "/usr/lib/?.lua",
@@ -18,7 +18,7 @@ function require(module,...)
end end
local modpath = module:gsub("%.", "/") local modpath = module:gsub("%.", "/")
local failed = {} local failed = {}
for _, path in ipairs(searchpaths) do for _, path in ipairs(kernel.searchpaths) do
local full_path = string.gsub(path, "%?", modpath) local full_path = string.gsub(path, "%?", modpath)
if full_path:sub(1,1)~="/" then if full_path:sub(1,1)~="/" then
full_path=kernel.currentTask.cwd..full_path full_path=kernel.currentTask.cwd..full_path

View File

@@ -1,173 +1,173 @@
--:Minify:-- --:Minify:--
local kernel = ... --local kernel = ...
--
local proxy = {} --local proxy = {}
local data = {} --local data = {}
--
proxy.address = "devfs0000" --proxy.address = "devfs0000"
proxy.isReadOnly = false --proxy.isReadOnly = false
proxy.spaceUsed = function() return 0 end --proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end --proxy.spaceTotal = function() return 0 end
proxy.makeDirectory = function() error("Permission denied") end --proxy.makeDirectory = function() error("Permission denied") end
proxy.remove = function() error("Permission denied") end --proxy.remove = function() error("Permission denied") end
proxy.setLabel = function() error("Permission denied") end --proxy.setLabel = function() error("Permission denied") end
proxy.getLabel = function() return "devfs" end --proxy.getLabel = function() return "devfs" end
proxy.attributes = function(path) return { --proxy.attributes = function(path) return {
type = proxy.type(path), -- type = proxy.type(path),
isReadOnly = false, -- isReadOnly = false,
size = 0, -- size = 0,
lastModified = 0, -- lastModified = 0,
created = 0, -- created = 0,
Permissions = "666", -- Permissions = "666",
owner = "root", -- owner = "root",
group = "root" -- group = "root"
} end --} end
--
local function getNode(path) --local function getNode(path)
local parts = string.split(path, "/") -- local parts = string.split(path, "/")
if parts[1] == "" then -- if parts[1] == "" then
table.remove(parts, 1) -- table.remove(parts, 1)
end -- end
--
local node = data -- local node = data
for _, part in ipairs(parts) do -- for _, part in ipairs(parts) do
if node[part] then -- if node[part] then
node = node[part] -- node = node[part]
else -- else
return nil -- return nil
end -- end
end -- end
--
return node -- return node
end --end
--
proxy.type = function(path) --proxy.type = function(path)
local node = getNode(path) -- local node = getNode(path)
if node then -- if node then
return node.type -- return node.type
else -- else
return nil -- return nil
end -- end
end --end
--
proxy.list = function(path) --proxy.list = function(path)
local node = getNode(path) -- local node = getNode(path)
if node and node.type == "directory" then -- if node and node.type == "directory" then
local content = table.keys(node) -- local content = table.keys(node)
table.remove(content, table.indexOf(content, "type")) -- table.remove(content, table.indexOf(content, "type"))
return content -- return content
else -- else
error("Not a directory") -- error("Not a directory")
end -- end
end --end
--
proxy.open = function(path, mode) --proxy.open = function(path, mode)
local node = getNode(path) -- local node = getNode(path)
if node and (node.type == "file" or node.type == "character device") then -- if node and (node.type == "file" or node.type == "character device") then
if mode == "r" then -- if mode == "r" then
return { -- return {
read = node.read, -- read = node.read,
close = function() end -- close = function() end
} -- }
elseif mode == "w" then -- elseif mode == "w" then
return { -- return {
write = node.write, -- write = node.write,
close = function() end -- close = function() end
} -- }
else -- else
error("Invalid mode") -- error("Invalid mode")
end -- end
else -- else
error("Not a file"..type(node)) -- error("Not a file"..type(node))
end -- end
end --end
--
local function newStringFile(content) --local function newStringFile(content)
return { -- return {
type = "file", -- type = "file",
read = function() return content end, -- read = function() return content end,
write = function(newContent) content = newContent end -- write = function(newContent) content = newContent end
} -- }
end --end
--
local function newDirectory() --local function newDirectory()
return { -- return {
type = "directory" -- type = "directory"
} -- }
end --end
--
data["random"] = { --data["random"] = {
type = "character device", -- type = "character device",
read = function(amount) -- read = function(amount)
local result = "" -- local result = ""
for _ = 1, amount do -- for _ = 1, amount do
result = result .. string.char(math.random(0, 255)) -- result = result .. string.char(math.random(0, 255))
end -- end
return result -- return result
end, -- end,
write = function() error("Permission denied") end -- write = function() error("Permission denied") end
} --}
--
data["null"] = { --data["null"] = {
type = "character device", -- type = "character device",
read = function() return "" end, -- read = function() return "" end,
write = function() end -- write = function() end
} --}
--
data["zero"] = { --data["zero"] = {
type = "character device", -- type = "character device",
read = function(amount) -- read = function(amount)
return string.rep("\0", amount) -- return string.rep("\0", amount)
end, -- end,
write = function() error("Permission denied") end -- write = function() error("Permission denied") end
} --}
--
data["rtc"] = { --data["rtc"] = {
type = "character device", -- type = "character device",
read = function() return kernel.computer:time() end, -- read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end -- write = function() error("Permission denied") end
} --}
--
data["rtc0"] = { --data["rtc0"] = {
type = "character device", -- type = "character device",
read = function() return kernel.computer:time() end, -- read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end -- write = function() error("Permission denied") end
} --}
--
data["eeprom"] = { --data["eeprom"] = {
type = "character device", -- type = "character device",
read = function() return kernel.computer:getEEPROM() end, -- read = function() return kernel.computer:getEEPROM() end,
write = function(data) -- write = function(data)
if kernel.uid ~= 0 then -- if kernel.uid ~= 0 then
error("Permission denied") -- error("Permission denied")
end -- end
kernel.computer:setEEPROM(data) -- kernel.computer:setEEPROM(data)
end -- end
} --}
--
local keyboard = kernel.newFifo() --local keyboard = kernel.newFifo()
local mouse = kernel.newFifo() --local mouse = kernel.newFifo()
data["input"] = newDirectory() --data["input"] = newDirectory()
data["input"]["keyboard"] = { --data["input"]["keyboard"] = {
type = "pipe", -- type = "pipe",
read = function(amount) -- read = function(amount)
return keyboard.pop() -- return keyboard.pop()
end, -- end,
write = function() error("Permission denied") end -- write = function() error("Permission denied") end
} --}
data["input"]["mouse"] = { --data["input"]["mouse"] = {
type = "pipe", -- type = "pipe",
read = function(amount) -- read = function(amount)
return mouse.pop() -- return mouse.pop()
end, -- end,
write = function() error("Permission denied") end -- write = function() error("Permission denied") end
} --}
--
data["pts"] = newDirectory() --data["pts"] = newDirectory()
--
kernel.devfs = {} --kernel.devfs = {}
kernel.devfs.keyboard = keyboard --kernel.devfs.keyboard = keyboard
kernel.devfs.mouse = mouse --kernel.devfs.mouse = mouse
kernel.devfs.proxy = proxy --kernel.devfs.proxy = proxy
kernel.devfs.data = data --kernel.devfs.data = data
kernel.vfs.virtdisk(proxy) --kernel.vfs.virtdisk(proxy)

View File

@@ -11,7 +11,7 @@ for i,v in ipairs(string.split(kernel.fstab,"\n")) do
end end
local path=v:sub(#id+4) local path=v:sub(#id+4)
if id~="$" then if id~="$" then
kernel.vfs.mount(id,path) kernel.vfs.mount(path, id)
end end
::endline:: ::endline::
end end

View File

@@ -1,76 +0,0 @@
--:Minify:--
local kernel = ...
local ports = {}
local signals = {}
local ipc = {}
function ipc.open(port)
if not ports[port] then
local handle = kernel.newUUID()
ports[port] = {owner = kernel.currentProcess.pid, handle = handle, messages = {}}
return ports[port].handle
end
error("Port already opened")
end
function ipc.close(port)
if ports[port] then
if ports[port].owner == kernel.currentProcess.pid then
ports[port] = nil
return true
else
error("Cannot close port you do not own")
end
end
error("Port not opened")
end
function ipc.send(port, message)
if ports[port] then
table.insert(ports[port].messages, {from = kernel.currentProcess.pid, message = message})
if signals[ports[port].owner] then
signals[ports[port].owner](port, message)
end
return true
end
error("Port not opened")
end
function ipc.receive(port)
if ports[port] then
if #ports[port].messages > 0 then
return table.remove(ports[port].messages, 1)
else
return nil
end
end
error("Port not opened")
end
function ipc.setSignalHandler(pid, handler)
signals[pid] = handler
end
function ipc.clearSignalHandler(pid)
signals[pid] = nil
end
function ipc.sendSignal(pid, ...)
coroutine.resumeWithTimeout(coroutine.create(function(...)
if signals[pid] then
signals[pid](...)
return true
end
end), 100)
return false
end
kernel.ipc = ipc
kernel.syscalls["ipc_open"] = ipc.open
kernel.syscalls["ipc_close"] = ipc.close
kernel.syscalls["ipc_send"] = ipc.send
kernel.syscalls["ipc_receive"] = ipc.receive
kernel.syscalls["ipc_setSignalHandler"] = ipc.setSignalHandler
kernel.syscalls["ipc_clearSignalHandler"] = ipc.clearSignalHandler
kernel.syscalls["ipc_sendSignal"] = ipc.sendSignal
kernel.log("Loaded IPC module")

View File

@@ -0,0 +1,10 @@
--:Minify:--
local kernel = ...
local socket = {}
function socket.socket()
end
kernel.socket=socket
kernel.log("Loaded socket module")

View File

@@ -1,66 +1,238 @@
--:Minify:-- --:Minify:--
local kernel = ... --local kernel = ...
local pam = {} --local pam = {}
kernel.pam = pam --kernel.pam = pam
local loggedIn = {} --local loggedIn = {}
--
local function getFile(path) --local function getFile(path)
local file = kernel.vfs.open(path, "r") -- local file = kernel.vfs.open(path, "r")
if not file then error("Failed to open file: "..path) end -- if not file then error("Failed to open file: "..path) end
local content = kernel.vfs.read(file, 1024000) -- local content = kernel.vfs.read(file, 1024000)
kernel.vfs.close(file) -- kernel.vfs.close(file)
return content -- return content
end --end
--
local blake2s = require("crypto.blake2s") --local blake2s
if not blake2s then error("Failed to load blake2s") end --
--do
if not kernel.vfs.exists("/etc/pam.d/secret") then -- local MOD32 = 2^32
local key = "" -- local function norm(x)
for i=1, 256 do -- return x % MOD32
key=key..string.char(math.random(1,255)) -- end
end --
local handle = kernel.vfs.open("/etc/pam.d/secret", "w") -- local function tobits(x)
kernel.vfs.write(handle, key) -- x = norm(x)
kernel.vfs.close(handle) -- local t = {}
end -- for i = 0, 31 do
-- local b = x % 2
local pepper = getFile("/etc/pam.d/secret") -- t[i] = b
-- x = (x - b) / 2
function pam.authenticate(username, password) -- end
local fpasswd = getFile("/etc/passwd") -- return t
local fshadow = getFile("/etc/shadow") -- end
--
local passwdLines = string.split(fpasswd, "\n") -- local function frombits(t)
local shadowLines = string.split(fshadow, "\n") -- local x = 0
-- local p = 1
local passwd = {} -- for i = 0, 31 do
local shadow = {} -- if t[i] == 1 then
for _, line in ipairs(passwdLines) do -- x = x + p
local fields = string.split(line, ":") -- end
passwd[fields[1]] = fields -- p = p * 2
end -- end
for _, line in ipairs(shadowLines) do -- return norm(x)
local fields = string.split(line, ":") -- end
shadow[fields[1]] = fields --
end -- local function bor(...)
-- local args = {...}
for user, fields in pairs(passwd) do -- if #args == 0 then return 0 end
if user == username then -- local bits = tobits(args[1])
local shadowPasswd = string.split(shadow[user][2], "$") -- for i = 2, #args do
local salt = shadowPasswd[2] -- local b = tobits(args[i])
local hashedPassword = blake2s(password .. salt, pepper) -- for j = 0, 31 do
if hashedPassword == shadowPasswd[3] then -- bits[j] = (bits[j] == 1 or b[j] == 1) and 1 or 0
loggedIn[username] = kernel.newUUID() -- end
return loggedIn[username] -- end
else -- return frombits(bits)
return false -- end
end --
end -- local function bxor(...)
end -- local args = {...}
end -- if #args == 0 then return 0 end
-- local bits = tobits(args[1])
function pam.authToken(username, token) -- for i = 2, #args do
return loggedIn[username] == token -- local b = tobits(args[i])
end -- for j = 0, 31 do
-- bits[j] = (bits[j] ~= b[j]) and 1 or 0
-- end
-- end
-- return frombits(bits)
-- end
--
-- local function lshift(x, n)
-- return norm(norm(x) * 2^n)
-- end
--
-- local function rshift(x, n)
-- return math.floor(norm(x) / 2^n)
-- end
--
-- local function rotr(x, n)
-- return bor(rshift(x, n), lshift(x, 32 - n))
-- end
--
-- local IV = {
-- 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
-- 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
-- }
--
-- local SIGMA = {
-- {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
-- {14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},
-- {11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},
-- {7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},
-- {9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},
-- {2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},
-- {12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},
-- {13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},
-- {6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},
-- {10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0}
-- }
--
-- local function G(v, a, b, c, d, x, y)
-- v[a] = (v[a] + v[b] + x) % MOD32
-- v[d] = rotr(bxor(v[d], v[a]), 16)
-- v[c] = (v[c] + v[d]) % MOD32
-- v[b] = rotr(bxor(v[b], v[c]), 12)
-- v[a] = (v[a] + v[b] + y) % MOD32
-- v[d] = rotr(bxor(v[d], v[a]), 8)
-- v[c] = (v[c] + v[d]) % MOD32
-- v[b] = rotr(bxor(v[b], v[c]), 7)
-- end
--
-- local function compress(h, block, t, last)
-- local v = {}
-- for i = 1, 8 do v[i] = h[i] end
-- for i = 1, 8 do v[i + 8] = IV[i] end
--
-- v[13] = bxor(v[13], t)
-- if last then
-- v[15] = bxor(v[15], 0xFFFFFFFF)
-- end
--
-- local m = {}
-- for i = 0, 15 do
-- local p = i * 4 + 1
-- m[i] =
-- (block:byte(p) or 0) +
-- ((block:byte(p + 1) or 0) * 0x100) +
-- ((block:byte(p + 2) or 0) * 0x10000) +
-- ((block:byte(p + 3) or 0) * 0x1000000)
-- end
--
-- for r = 1, 10 do
-- local s = SIGMA[r]
-- G(v,1,5,9,13, m[s[1]], m[s[2]])
-- G(v,2,6,10,14, m[s[3]], m[s[4]])
-- G(v,3,7,11,15, m[s[5]], m[s[6]])
-- G(v,4,8,12,16, m[s[7]], m[s[8]])
-- G(v,1,6,11,16, m[s[9]], m[s[10]])
-- G(v,2,7,12,13, m[s[11]], m[s[12]])
-- G(v,3,8,9,14, m[s[13]], m[s[14]])
-- G(v,4,5,10,15, m[s[15]], m[s[16]])
-- end
--
-- for i = 1, 8 do
-- h[i] = bxor(h[i], v[i], v[i + 8])
-- end
-- end
--
-- function blake2s(msg, key)
-- key = key or ""
--
-- local h = {}
-- for i = 1, 8 do h[i] = IV[i] end
--
-- local outlen = 32 -- bytes
-- h[1] = bxor(
-- h[1],
-- 0x01010000 + lshift(#key, 8) + outlen
-- )
--
-- local t = 0
--
-- if #key > 0 then
-- local block = key .. string.rep("\0", 64 - #key)
-- t = #key
-- compress(h, block, t, false)
-- end
--
-- for i = 1, #msg, 64 do
-- local block = msg:sub(i, i + 63)
-- if #block < 64 then
-- block = block .. string.rep("\0", 64 - #block)
-- end
-- t = t + math.min(64, #msg - i + 1)
-- compress(h, block, t, i + 64 > #msg)
-- end
--
-- local out = ""
-- for i = 1, 8 do
-- out = out .. string.format("%08x", h[i])
-- end
-- return out
-- end
--end
--
--if not blake2s then error("Failed to load blake2s") end
--
--if not kernel.vfs.exists("/etc/pam.d/secret") then
-- local key = ""
-- for i=1, 256 do
-- key=key..string.char(math.random(1,255))
-- end
-- local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
-- kernel.vfs.write(handle, key)
-- kernel.vfs.close(handle)
--end
--
--local pepper = getFile("/etc/pam.d/secret")
--
--function pam.authenticate(username, password)
-- local fpasswd = getFile("/etc/passwd")
-- local fshadow = getFile("/etc/shadow")
--
-- local passwdLines = string.split(fpasswd, "\n")
-- local shadowLines = string.split(fshadow, "\n")
--
-- local passwd = {}
-- local shadow = {}
-- for _, line in ipairs(passwdLines) do
-- local fields = string.split(line, ":")
-- passwd[fields[1]] = fields
-- end
-- for _, line in ipairs(shadowLines) do
-- local fields = string.split(line, ":")
-- shadow[fields[1]] = fields
-- end
--
-- for user, fields in pairs(passwd) do
-- if user == username then
-- local shadowPasswd = string.split(shadow[user][2], "$")
-- local salt = shadowPasswd[2]
-- local hashedPassword = blake2s(password .. salt, pepper)
-- if hashedPassword == shadowPasswd[3] then
-- loggedIn[username] = kernel.newUUID()
-- return loggedIn[username]
-- else
-- return false
-- end
-- end
-- end
--end
--
--function pam.authToken(username, token)
-- return loggedIn[username] == token
--end
--
--

View File

@@ -16,7 +16,9 @@ function sys.spawn(func, name, envars, args, tgid)
kernel.log("Task "..tostring(id).." exited with err: "..tostring(err), "ERROR", 2) kernel.log("Task "..tostring(id).." exited with err: "..tostring(err), "ERROR", 2)
end end
tasks[tostring(id)].status="Z" tasks[tostring(id)].status="Z"
if type(err)=="number" then
tasks[tostring(id)].exit=err tasks[tostring(id)].exit=err
end
else else
if kernel.config.logTaskExit then if kernel.config.logTaskExit then
if err then if err then
@@ -26,8 +28,10 @@ function sys.spawn(func, name, envars, args, tgid)
end end
end end
tasks[tostring(id)].status="Z" tasks[tostring(id)].status="Z"
if type(err)=="number" then
tasks[tostring(id)].exit=err tasks[tostring(id)].exit=err
end end
end
end), end),
name=name or ("task"..tostring(id)), name=name or ("task"..tostring(id)),
envars=envars or kernel.currentTask.envars, envars=envars or kernel.currentTask.envars,
@@ -79,8 +83,6 @@ function sys.getTaskInfo(pid)
end end
return { return {
name=task.name, name=task.name,
envars=table.deepcopy(task.envars),
args=table.deepcopy(task.args),
status=task.status, status=task.status,
pid=task.pid, pid=task.pid,
tgid=task.tgid, tgid=task.tgid,
@@ -173,7 +175,7 @@ end
function sys.list() function sys.list()
local ret={} local ret={}
for i,_ in ipairs(tasks) do for i,_ in pairs(tasks) do
ret[i]=sys.getTaskInfo(i) ret[i]=sys.getTaskInfo(i)
end end
return ret return ret
@@ -187,18 +189,33 @@ function sys.setEnviron(key, value)
kernel.currentTask.envars[key]=value kernel.currentTask.envars[key]=value
end end
kernel.syscalls["HPV_spawn"]=sys.spawn function sys.exit(code)
kernel.syscalls["HPV_sleep"]=sys.sleep if kernel.config.logTaskExit then
kernel.syscalls["HPV_getTaskInfo"]=sys.getTaskInfo if code then
kernel.syscalls["HPV_collect"]=sys.collect kernel.log("Task "..tostring(kernel.currentTask.pid).." exited with code: "..tostring(code), "INFO")
kernel.syscalls["HPV_kill"]=sys.kill else
kernel.syscalls["HPV_stop"]=sys.stop kernel.log("Task "..tostring(kernel.currentTask.pid).." exited without code", "INFO")
kernel.syscalls["HPV_continue"]=sys.continue end
kernel.syscalls["HPV_getPid"]=sys.getPid end
kernel.syscalls["HPV_list"]=sys.list tasks[tostring(kernel.currentTask.pid)].status="Z"
kernel.syscalls["HPV_setEnviron"]=sys.setEnviron if type(code)=="number" then
kernel.syscalls["HPV_getEnviron"]=sys.getEnviron tasks[tostring(kernel.currentTask.pid)].exit=code
kernel._G.sleep=function(...)coroutine.yield("syscall","HPV_sleep",...)end end
end
kernel.syscalls["spawn"]=sys.spawn
kernel.syscalls["sleep"]=sys.sleep
kernel.syscalls["getTaskInfo"]=sys.getTaskInfo
kernel.syscalls["collect"]=sys.collect
kernel.syscalls["kill"]=sys.kill
kernel.syscalls["stop"]=sys.stop
kernel.syscalls["continue"]=sys.continue
kernel.syscalls["getPid"]=sys.getPid
kernel.syscalls["list"]=sys.list
kernel.syscalls["setEnviron"]=sys.setEnviron
kernel.syscalls["getEnviron"]=sys.getEnviron
kernel.syscalls["exit"]=sys.exit
kernel._G.sleep=function(...)coroutine.yield("syscall","sleep",...)end
local function reapDeadTasks() local function reapDeadTasks()
for pid, task in pairs(tasks) do for pid, task in pairs(tasks) do
@@ -216,7 +233,7 @@ local function reapDeadTasks()
task.timeSlice = nil task.timeSlice = nil
task.syscallReturn = nil task.syscallReturn = nil
task.sleep = nil task.sleep = nil
for k,v in pairs(task.fd) do for v,_ in ipairs(task.fd) do
kernel.vfs.close(v) kernel.vfs.close(v)
end end
task.fd = nil task.fd = nil

View File

@@ -1,90 +1,91 @@
--:Minify:-- --:Minify:--
local kernel=... local kernel=...
kernel.tty={} local tty={}
kernel.tty.inst={} kernel.tty=tty
tty.inst={}
function kernel.tty.register(tty, ttyo) function tty.register(ttyn, ttyo)
kernel.tty.inst[tty]=ttyo tty.inst[ttyn]=ttyo
end end
function kernel.tty.print(text) function tty.print(text)
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
kernel.tty.inst[term].print(text) tty.inst[term].print(text)
end end
end end
function kernel.tty.printInline(text) function tty.printInline(text)
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
kernel.tty.inst[term].printInline(text) tty.inst[term].printInline(text)
end end
end end
function kernel.tty.size() function tty.size()
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].size() return tty.inst[term].size()
end end
end end
function kernel.tty.setCursorPos(x,y) function tty.setCursorPos(x,y)
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].setCursorPos(x,y) return tty.inst[term].setCursorPos(x,y)
end end
end end
function kernel.tty.getCursorPos() function tty.getCursorPos()
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].getCursorPos() return tty.inst[term].getCursorPos()
end end
end end
function kernel.tty.clear() function tty.clear()
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].clear() return tty.inst[term].clear()
end end
end end
function kernel.tty.setTextColor(color) function tty.setTextColor(color)
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].setTextColor(color) return tty.inst[term].setTextColor(color)
end end
end end
function kernel.tty.setBackgroundColor(color) function tty.setBackgroundColor(color)
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].setBackgroundColor(color) return tty.inst[term].setBackgroundColor(color)
end end
end end
function kernel.tty.scroll(n) function tty.scroll(n)
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] then if term and tty.inst[term] then
return kernel.tty.inst[term].scroll(n) return tty.inst[term].scroll(n)
end end
end end
function kernel.tty.getTextColor() function tty.getTextColor()
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] and kernel.tty.inst[term].getTextColor then if term and tty.inst[term] and tty.inst[term].getTextColor then
return kernel.tty.inst[term].getTextColor() return tty.inst[term].getTextColor()
end end
end end
function kernel.tty.getBackgroundColor() function tty.getBackgroundColor()
local term=kernel.currentTask.term local term=kernel.currentTask.term
if term and kernel.tty.inst[term] and kernel.tty.inst[term].getBackgroundColor then if term and tty.inst[term] and tty.inst[term].getBackgroundColor then
return kernel.tty.inst[term].getBackgroundColor() return tty.inst[term].getBackgroundColor()
end end
end end
function kernel.tty.bind(ttyid) function tty.bind(ttyid)
if not ttyid then if not ttyid then
return false, "No TTY ID specified" return false, "No TTY ID specified"
end end
@@ -95,33 +96,34 @@ function kernel.tty.bind(ttyid)
return true return true
end end
function kernel.tty.unbind() function tty.unbind()
kernel.currentTask.term=false kernel.currentTask.term=false
end end
function kernel.tty.isBound() function tty.isBound()
return kernel.currentTask.term ~= nil return kernel.currentTask.term ~= nil
end end
function kernel.tty.getBoundTTY() function tty.getBoundTTY()
return kernel.currentTask.term return kernel.currentTask.term
end end
kernel.syscalls["TTY_print"]=kernel.tty.print local sys=kernel.syscalls
kernel.syscalls["TTY_printInline"]=kernel.tty.printInline sys["TTY_print"]=tty.print
kernel.syscalls["TTY_size"]=kernel.tty.size sys["TTY_printInline"]=tty.printInline
kernel.syscalls["TTY_setCursorPos"]=kernel.tty.setCursorPos sys["TTY_size"]=tty.size
kernel.syscalls["TTY_getCursorPos"]=kernel.tty.getCursorPos sys["TTY_setCursorPos"]=tty.setCursorPos
kernel.syscalls["TTY_clear"]=kernel.tty.clear sys["TTY_getCursorPos"]=tty.getCursorPos
kernel.syscalls["TTY_setTextColor"]=kernel.tty.setTextColor sys["TTY_clear"]=tty.clear
kernel.syscalls["TTY_setBackgroundColor"]=kernel.tty.setBackgroundColor sys["TTY_setTextColor"]=tty.setTextColor
kernel.syscalls["TTY_scroll"]=kernel.tty.scroll sys["TTY_setBackgroundColor"]=tty.setBackgroundColor
kernel.syscalls["TTY_getTextColor"]=kernel.tty.getTextColor sys["TTY_scroll"]=tty.scroll
kernel.syscalls["TTY_getBackgroundColor"]=kernel.tty.getBackgroundColor sys["TTY_getTextColor"]=tty.getTextColor
kernel.syscalls["TTY_bind"]=kernel.tty.bind sys["TTY_getBackgroundColor"]=tty.getBackgroundColor
kernel.syscalls["TTY_unbind"]=kernel.tty.unbind sys["TTY_bind"]=tty.bind
kernel.syscalls["TTY_isBound"]=kernel.tty.isBound sys["TTY_unbind"]=tty.unbind
kernel.syscalls["TTY_getBoundTTY"]=kernel.tty.getBoundTTY sys["TTY_isBound"]=tty.isBound
sys["TTY_getBoundTTY"]=tty.getBoundTTY
kernel.log("TTY module loaded attempting to register console tty") kernel.log("TTY module loaded attempting to register console tty")
kernel.status="init" kernel.status="init"

View File

@@ -3,8 +3,11 @@ local kernel = ...
kernel.log("Loading init system...") kernel.log("Loading init system...")
kernel.log("InitPath: "..kernel.config.initPath) kernel.log("InitPath: "..kernel.config.initPath)
local handle = kernel.vfs.open(kernel.config.initPath, "r") local handle = kernel.vfs.open(kernel.config.initPath, "r")
kernel.log("O")
local data = kernel.vfs.read(handle, 1024 * 1024 * 4) local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
kernel.log("R")
kernel.vfs.close(handle) kernel.vfs.close(handle)
kernel.log("C")
local initFunc, err = load(data, "@sysinit") local initFunc, err = load(data, "@sysinit")
if not initFunc then if not initFunc then

View File

@@ -0,0 +1,23 @@
local fs=require("sys.fs")
local units=fs.list("/usr/lib/hunit/")
fs.mkdir("/tmp/hunit/")
local errors={}
for i,v in ipairs(units) do
print("running unit "..v)
local code=fs.readAllText("/usr/lib/hunit/"..v)
local func, err=load(code, "@"..v)
if not func then
print(" [ERROR]:"..err)
end
---@diagnostic disable-next-line: param-type-mismatch
local ok, err=pcall(func)
if not ok then
print(" [ERROR]:"..err)
table.insert(errors, v)
else
print(" [SUCCESS]")
end
end
print(tostring(#errors).." units failed")
return 0

View File

@@ -0,0 +1,3 @@
local fs = require("sys.fs")
assert(fs.mkdir("/tmp/hunit/testdir"), "failed to make directory")
assert(fs.isDir("/tmp/hunit/testdir"), "directory does not exist")

View File

@@ -0,0 +1,10 @@
local fd = syscall.VFS_open("/tmp/hunit/testfile.txt", "w")
syscall.VFS_write(fd, "This is a test file")
syscall.VFS_close(fd)
local fd = syscall.VFS_open("/tmp/hunit/testfile.txt", "r")
local text = syscall.VFS_read(fd, 64)
syscall.VFS_close(fd)
if text~="This is a test file" then
error("File failed to write/read")
end

View File

@@ -1,3 +1,4 @@
---@diagnostic disable: undefined-global
local diskpath="put your path here" local diskpath="put your path here"
periphemu.create("right", "drive") periphemu.create("right", "drive")
disk.insertDisk("right", diskpath) disk.insertDisk("right", diskpath)
@@ -7,4 +8,5 @@ file.close()
local func = load(text, "@bios.lua") local func = load(text, "@bios.lua")
---@diagnostic disable-next-line: need-check-nil
func("/disk") func("/disk")