diff --git a/Src/Hyperion-firmware-cct/boot/cct/boot.lua b/Src/Hyperion-firmware-cct/boot/cct/boot.lua index 97759c9..ee4bc1e 100644 --- a/Src/Hyperion-firmware-cct/boot/cct/boot.lua +++ b/Src/Hyperion-firmware-cct/boot/cct/boot.lua @@ -249,6 +249,14 @@ local ok, err = xpcall(function() return value end + local allscreens = {apis.peripheral.find("monitor")} + for i=1, #allscreens do + allscreens[i].setTextScale(.5) + allscreens[i].clear() + allscreens[i].setCursorPos(1,1) + allscreens[i].write("Initializing...") + end + local EFI = { getEpochMs = function() return apis.os.epoch("utc") end, getUptime = function() return apis.os.clock() * 1000 end, @@ -303,7 +311,8 @@ local ok, err = xpcall(function() h.close() end, firmware=apis, - reboot=false + reboot=false, + beep=function() end } apis.term.setBackgroundColor(0x8000) @@ -340,7 +349,7 @@ local ok, err = xpcall(function() end end - write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n") + EFI.screenCtl:print("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n") while true do local status, err = coroutine.resumeWithTimeout(kernelCoro, 50) diff --git a/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/24_periph.kmod b/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod similarity index 100% rename from Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/24_periph.kmod rename to Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod diff --git a/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/40_http.kmod b/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/22_http.kmod similarity index 100% rename from Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/40_http.kmod rename to Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/22_http.kmod diff --git a/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod b/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod index 6f1698d..8c9bcb0 100644 --- a/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod +++ b/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod @@ -1,7 +1,6 @@ --:Minify:-- local kernel = ... local peripheral=kernel.cct.peripheral -local keys=kernel.apis.keys local colors = { [0xFFFFFF]=0x0001, @@ -146,7 +145,7 @@ local function write(text, term) end kernel.devfs.data.tty={} -local ctrl,alt = false, false +kernel.cct.ctrl,kernel.cct.alt = false, false local function serializeBool(bool) if bool then @@ -222,7 +221,7 @@ local function newtty(obj, id, ev) return bg end, gctrl=function() - return serializeBool(ctrl)..";"..serializeBool(alt) + return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt) end, gplt=function() return plt @@ -242,83 +241,7 @@ local function newtty(obj, id, ev) end local fifo = kernel.newFifo() - -kernel.processes.cctmond = function() - local timeout = false - while true do - local event = {kernel.EFI:getMachineEvent()} - - if event[1] then - local eventType = event[1] - local charOrKey = event[3] - - local ctrlKeyMap = { - [keys.a]=1, [keys.b]=2, [keys.c]=3, - [keys.d]=4, [keys.e]=5, [keys.f]=6, - [keys.g]=7, [keys.h]=8, [keys.i]=9, - [keys.j]=10, [keys.k]=11, [keys.l]=12, - [keys.m]=13, [keys.n]=14, [keys.o]=15, - [keys.p]=16, [keys.q]=17, [keys.r]=18, - [keys.s]=19, [keys.t]=20, [keys.u]=21, - [keys.v]=22, [keys.w]=23, [keys.x]=24, - [keys.y]=25, [keys.z]=26, - } - - if eventType == "keyPressed" then - if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then - ctrl = true - elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then - alt = true - end - - if ctrl then - local ctrlByte = ctrlKeyMap[charOrKey] - if ctrlByte then - if ctrlByte == 3 then - for _, task in ipairs(syscall.getTasks()) do - syscall.sigsend(task, 1) - end - else - fifo.push(string.char(ctrlByte)) - end - end - else - local specialKeyMap = { - [keys.up] = "", - [keys.down] = "", - [keys.right] = "", - [keys.left] = "", - [keys.home] = "", - [keys["end"]] = "", - [keys.pageUp] = "[5~", - [keys.pageDown] = "[6~", - [keys.delete] = "[3~", - } - local special = specialKeyMap[charOrKey] - if special then fifo.push(special) end - end - - elseif eventType == "keyReleased" then - if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then - ctrl = false - elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then - alt = false - end - - elseif eventType == "keyTyped" then - if charOrKey then fifo.push(charOrKey) end - end - - timeout = false - else - timeout = true - end - - if timeout then - sleep(0.05) - end - end -end +kernel.cct.fifo=fifo newtty(kernel.apis.term, "1", fifo.pop) diff --git a/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/30_deamon.kmod b/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/30_deamon.kmod new file mode 100644 index 0000000..f3d4acc --- /dev/null +++ b/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/30_deamon.kmod @@ -0,0 +1,86 @@ +--:Minify:-- +local kernel=... +local keys=kernel.apis.keys + +kernel.processes.cctdeamon = function() + local timeout = false + while true do + local event = {kernel.EFI:getMachineEvent()} + + if event[1] then + local eventType = event[1] + local charOrKey = event[3] + + local ctrlKeyMap = { + [keys.a]=1, [keys.b]=2, [keys.c]=3, + [keys.d]=4, [keys.e]=5, [keys.f]=6, + [keys.g]=7, [keys.h]=8, [keys.i]=9, + [keys.j]=10, [keys.k]=11, [keys.l]=12, + [keys.m]=13, [keys.n]=14, [keys.o]=15, + [keys.p]=16, [keys.q]=17, [keys.r]=18, + [keys.s]=19, [keys.t]=20, [keys.u]=21, + [keys.v]=22, [keys.w]=23, [keys.x]=24, + [keys.y]=25, [keys.z]=26, + } + + if eventType == "keyPressed" then + if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then + kernel.cct.ctrl = true + elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then + kernel.cct.alt = true + end + + if kernel.cct.ctrl then + local ctrlByte = ctrlKeyMap[charOrKey] + if ctrlByte then + if ctrlByte == 3 then + for _, task in ipairs(syscall.getTasks()) do + syscall.sigsend(task, 1) + end + else + kernel.cct.fifo.push(string.char(ctrlByte)) + end + end + else + local specialKeyMap = { + [keys.up] = "", + [keys.down] = "", + [keys.right] = "", + [keys.left] = "", + [keys.home] = "", + [keys["end"]] = "", + [keys.pageUp] = "[5~", + [keys.pageDown] = "[6~", + [keys.delete] = "[3~", + } + local special = specialKeyMap[charOrKey] + if special then kernel.cct.fifo.push(special) end + end + + elseif eventType == "keyReleased" then + if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then + kernel.cct.ctrl = false + elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then + kernel.cct.alt = false + end + + elseif eventType == "keyTyped" then + if charOrKey then kernel.cct.fifo.push(charOrKey) end + elseif eventType == "http_success" then + kernel.cct.httpqueue[event[2]]=nil + kernel.cct.httpresponse[event[2]]=event[3] + elseif eventType == "http_failure" then + kernel.cct.httpqueue[event[2]]=nil + kernel.cct.httperror[event[2]]=event[3] + end + + timeout = false + else + timeout = true + end + + if timeout then + sleep(0.05) + end + end +end \ No newline at end of file diff --git a/Src/Hyperion-kernel/boot/kernel.lua b/Src/Hyperion-kernel/boot/kernel.lua index 38f56b2..4cc2099 100644 --- a/Src/Hyperion-kernel/boot/kernel.lua +++ b/Src/Hyperion-kernel/boot/kernel.lua @@ -1,5 +1,6 @@ --:Minify:-- local EFI=... +EFI.beep(440, 500) local screen=EFI.screenCtl local ifs=EFI.initfs local disks=EFI.disks diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod index ab49a8a..7633831 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod @@ -499,7 +499,7 @@ local function checkperms(meta, mode) local bitmap = { r = {owner = 5, group = 3, everyone = 1}, w = {owner = 4, group = 2, everyone = 0}, - a = {owner = 4, group = 2, everyone = 0}, + a = {owner = 4, group = 2, everyone = 0} } local m = bitmap[mode] if not m then error("EINVAL") end @@ -544,7 +544,6 @@ local function newFileObj(handle, mode, path, meta, ftype) end function vfs.newfd(fdobj) - checkSystemLimit(); total = total + 1 local fd = allocFD(kernel.currentTask) kernel.currentTask.fd[fd] = fdobj return fd @@ -595,6 +594,21 @@ function vfs.open(path, mode) local fd = allocFD(task) local disk, diskPath = resolvePath(path) if not disk then error("NODISK") end + if (mode=="w" or mode=="a") and disk:isReadOnly() then error("ERDONLY") end + + if kernel.unixSockets[normalizePath(path)] then + local meta = kernel.unixSockets[normalizePath(path)].meta + if kernel.uid~=0 or kernel.uid~=meta.owner then + local groups = (task and task.groups) or kernel.groups or {} + local access=false + for _, gid in ipairs(groups) do + if gid == meta.group then access=true end + end + if not access then error("EACCES") end + end + task[fd]=kernel.unixSockets[normalizePath(path)] + return fd + end local meta = getFileMeta(path) local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath) @@ -696,10 +710,18 @@ function vfs.sendfile(outfd, infd, count) end function vfs.stat(path) - local disk, diskPath = resolvePath(path) - local meta = getFileMeta(path) - local ok, attrs = pcall(disk.attributes, disk, diskPath) - if not ok then attrs = { size=0, modified=0, created=0 } end + local attrs + local meta + if meta.etype == 0x02 then + attrs = { size=0, modified=0, created=0 } + else + local disk, diskPath = resolvePath(path) + meta = getFileMeta(path) + local ok + ok, attrs = pcall(disk.attributes, disk, diskPath) + if not ok then attrs = { size=0, modified=0, created=0 } end + end + return { size = attrs.size, modified = attrs.modified, @@ -714,15 +736,15 @@ end function vfs.lstat(path) local meta = getFileMeta(path, true) - local attrs - if meta.etype == 0x01 then + if meta.etype == 0x01 or meta.etype == 0x02 then attrs = { size=0, modified=0, created=0 } else local disk, diskPath = resolvePath(path, true) local ok, a = pcall(disk.attributes, disk, diskPath) attrs = ok and a or { size=0, modified=0, created=0 } end + return { size = attrs.size, modified = attrs.modified, @@ -739,8 +761,15 @@ end function vfs.fstat(fd) local file = kernel.currentTask.fd[fd] if not file then error("EBADF") end - local disk, diskPath = resolvePath(file.path) - local attrs = disk:attributes(diskPath) + local attrs + if file.meta.etype == 0x02 then + attrs = { size=0, modified=0, created=0 } + else + local disk, diskPath = resolvePath(file.path, true) + local ok, a = pcall(disk.attributes, disk, diskPath) + attrs = ok and a or { size=0, modified=0, created=0 } + end + return { size = attrs.size, modified = attrs.modified, @@ -769,6 +798,14 @@ function vfs.listdir(path) end end + for k,v in pairs(kernel.unixSockets) do + local p=normalizePath(path) + if k:match("^(.*)/[^/]+$")==p then + seen[v.name]=true + table.insert(out, v.name) + end + end + local mp if diskPath == "/" then mp = ".meta" @@ -797,6 +834,7 @@ function vfs.mkdir(path) local parentMeta = getFileMeta(parent) checkperms(parentMeta, "w") local disk, diskPath = resolvePath(path) + if disk:isReadOnly() then error("ERDONLY") end disk:makeDirectory(diskPath) local task = kernel.currentTask local euid = (task and (task.euid or task.uid)) or kernel.uid @@ -818,8 +856,13 @@ function vfs.remove(path) local meta = getFileMeta(path, true) - if kernel.unixSockets and kernel.unixSockets[path] then - kernel.unixSockets[path] = nil + if kernel.unixSockets and kernel.unixSockets[normalizePath(path)] then + if kernel.uid ~= 0 then + if kernel.unixSockets[normalizePath(path)].meta.owner~=kernel.uid then + error("EACCES") + end + end + kernel.unixSockets[normalizePath(path)] = nil end if meta.etype == 0x01 then @@ -828,6 +871,7 @@ function vfs.remove(path) if parent == "" then parent = "/" end local name = norm:match("[^/]+$") local disk, parentDiskPath = resolveMount(parent) + if disk:isReadOnly() then error("ERDONLY") end local mp if parentDiskPath == "/" then mp = ".meta" else mp = parentDiskPath:gsub("^/+", "") .. "/.meta" end @@ -844,6 +888,7 @@ function vfs.remove(path) if f2.close then f2.close() end else local disk, diskPath = resolvePath(path) + if disk:isReadOnly() then error("ERDONLY") end disk:remove(diskPath) end end @@ -852,6 +897,8 @@ function vfs.symlink(target, linkPath) if type(target) ~= "string" or type(linkPath) ~= "string" then error("EINVAL") end local norm = normalizePath(linkPath) local parent = norm:match("^(.*)/[^/]+$") or "/" + local disk = resolveMount(linkPath) + if disk:isReadOnly() then error("ERDONLY") end if parent == "" then parent = "/" end local name = norm:match("[^/]+$") if not name then error("EINVAL") end @@ -881,7 +928,13 @@ function vfs.readlink(path) end function vfs.access(path, mode) - local meta = getFileMeta(path) + local meta + if kernel.unixSockets[normalizePath(path)] then + meta = kernel.unixSockets[normalizePath(path)].meta + else + meta = getFileMeta(path) + end + for i = 1, #mode do checkperms(meta, mode:sub(i,i)) end @@ -892,6 +945,8 @@ local function updateMeta(path, fn, noFollow) local real = namei(path, noFollow) local norm = real local parent = norm:match("^(.*)/[^/]+$") or "/" + local disk = resolveMount(path) + if disk:isReadOnly() then error("ERDONLY") end if parent == "" then parent = "/" end local name = norm:match("[^/]+$") if not name then error("EINVAL") end @@ -918,6 +973,9 @@ local function updateMeta(path, fn, noFollow) end function vfs.chmod(path, perms) + if kernel.unixSockets[normalizePath(path)] then error("EINVAL") end + local disk = resolveMount(path) + if disk:isReadOnly() then error("ERDONLY") end local meta = getFileMeta(path) local euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid if euid ~= 0 and euid ~= meta.owner then error("EACCES") end @@ -927,10 +985,14 @@ end function vfs.fchmod(fd, perms) local file = kernel.currentTask.fd[fd] if not file then error("EBADF") end + if file.etype==0x02 then error("EINVAL") end vfs.chmod(file.path, perms) end function vfs.chown(path, uid, gid) + if kernel.unixSockets[normalizePath(path)] then error("EINVAL") end + local disk = resolveMount(path) + if disk:isReadOnly() then error("ERDONLY") end local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid if _euid ~= 0 then error("EPERM") end updateMeta(path, function(e) e.owner = uid; e.group = gid end) @@ -939,10 +1001,12 @@ end function vfs.fchown(fd, uid, gid) local file = kernel.currentTask.fd[fd] if not file then error("EBADF") end + if file.etype==0x02 then error("EINVAL") end vfs.chown(file.path, uid, gid) end function vfs.exists(path) + if kernel.unixSockets[normalizePath(path)] then return true end local meta = getFileMeta(path, true) if meta.etype == 0x01 then return true end local ok, disk, diskPath = pcall(resolvePath, path) @@ -957,6 +1021,9 @@ end function vfs.type(path) local meta = getFileMeta(path, true) if meta.etype == 0x01 then return "symlink" end + if kernel.unixSockets[normalizePath(path)] then + return "socket" + end local ok, disk, diskPath = pcall(resolvePath, path) if not ok then return nil end return disk:type(diskPath) diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod index 8dc6790..028c343 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod @@ -6,7 +6,7 @@ local data = {} proxy.address = "procfs0000" proxy.isvirt = true -proxy.isReadOnly = function() return false end +proxy.isReadOnly = function() return true end proxy.spaceUsed = function() return 0 end proxy.spaceTotal = function() return 0 end proxy.makeDirectory = function() error("EACCES") end diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod index e647a10..82d11e3 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod @@ -12,13 +12,24 @@ function signal.sigsend(pid, sig) end function signal.sigcatch(handler) - kernel.currentTask.sigh=handler - if not kernel.currentTask.sigq then kernel.currentTask.sigq={} end + local task=kernel.currentTask + task.sigh=handler + if not task.sigq then task.sigq={} end + local handle={ + error="", + active=true + } + if task.sigd then task.sigd.active=false; end + task.sigd=handle + return handle end function signal.sigignore() - kernel.currentTask.sigh=nil - kernel.currentTask.sigq=nil + local task=kernel.currentTask + task.sigh=nil + task.sigq=nil + if task.sigd then task.sigd.active=false end + task.sigd=nil end local s=kernel.syscalls diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod index 6312404..e69f1f5 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod @@ -17,7 +17,42 @@ local kernel=... local socket={} +socket.handlers={} kernel.socket=socket +function socket.registerProtocal(protocal, handler) + socket.handlers[protocal] = handler +end + +function socket.socket() + local P=kernel.vfs.P + local data=kernel.newFifo() + local isClosed=false + kernel.vfs.newfd({ + handle={ + read=function() if isClosed then error("ECCON") end return data.read() end, + write=function() if isClosed then error("ECCON") end return data.write() end, + close=function() isClosed = true end + }, + type="socket", + refcount=1, + + meta={ + owner=kernel.currentTask.uid, + group=kernel.currentTask.uid, + etype=2, + perms=P.OWNER_R+P.OWNER_W+P.GROUP_R+P.GROUP_W + }, + isvirt=true + }) +end + +function socket.connect(fd, address) + +end + +function socket.listen(fd, backlog) + +end kernel.log("Loaded socket module") diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/21_unixsockets.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/21_unixsockets.kmod new file mode 100644 index 0000000..a437c9c --- /dev/null +++ b/Src/Hyperion-kernel/lib/modules/hyperion/21_unixsockets.kmod @@ -0,0 +1,3 @@ +--:Minify:-- +local kernel=... +kernel.unixSockets={} \ No newline at end of file diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod index 6317c8d..f859fcf 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod @@ -156,7 +156,6 @@ end function sys.sleep(s) kernel.currentTask.status = "S" kernel.currentTask.sleep = kernel.EFI:getEpochMs() + s * 1000 - coroutine.yield() end function sys.getTask(pid) @@ -343,40 +342,42 @@ function kernel.main() local taskTimes = {} for pid, task in pairs(tasks) do + kernel.currentTask = task + kernel.uid = task.euid or task.uid + kernel.process = task.name + if task.status == "S" and kernel.EFI:getEpochMs() >= task.sleep then task.status = "R" task.sleep = 0 end - if task.status == "R" then - kernel.currentTask = task + if task.status == "D" then + if task.ksh then + coroutine.resume(task.ksh) + end + end - kernel.uid = task.euid or task.uid - kernel.process = task.name + if task.status == "R" then N = N + 1 task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha))) if task.sigq and #task.sigq ~= 0 and task.sigh then local coro = coroutine.create(task.sigh) - local sigret = { coroutine.resume(coro, table.remove(task.sigq, 1)) } - while coroutine.status(coro) ~= "dead" do - if sigret[1] == false then break end - if sigret[2] == "syscall" then - local scname = sigret[3] - local sysret - if kernel.syscalls[scname] then - sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(sigret, 4)) } - else - sysret = { false, "Unknown syscall: " .. tostring(scname) } - end - if not sysret[1] then - sigret = { coroutine.resume(coro, false, sysret[2]) } - else - sigret = { coroutine.resume(coro, true, table.unpack(sysret, 2)) } - end - else - sigret = { coroutine.resume(coro) } + local status,err=coroutine.resumeWithTimeout(coro, 100, table.remove(task.sigq, 1)) + if status=="error" then + task.sigd.error=err + task.sigd.active=false + task.sigh=nil + task.sigq=nil + task.sigd=nil + elseif status=="success" then + if err=="syscall" then + task.sigd.error="Cannot execute syscalls from signals" + task.sigd.active=false + task.sigh=nil + task.sigq=nil + task.sigd=nil end end end @@ -386,7 +387,11 @@ function kernel.main() local ret if kernel.config.preempt then - ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) } + if not task.debugger then + ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) } + else + ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) } + end else ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) } end diff --git a/Src/hysh/bin/ls b/Src/hysh/bin/ls index 80e08ce..a37877f 100644 --- a/Src/hysh/bin/ls +++ b/Src/hysh/bin/ls @@ -110,10 +110,12 @@ if cloptions.l then local stat = syscall.lstat and syscall.lstat(fullPath) or syscall.stat(fullPath) local isDir = fs.isDir(fullPath) local isSym = stat and stat.etype == 0x01 + local isSock = stat and stat.etype == 0x02 local typeChar - if isSym then typeChar = "l" + if isSym then typeChar = "l" elseif isDir then typeChar = "d" + elseif isSock then typeChar = "s" else typeChar = "-" end local pstr @@ -136,14 +138,14 @@ if cloptions.l then printInline(tostring(mtime) .. " ") if isSym then - syscall.devctl(1, "sfgc", 0xFF00FF) + syscall.devctl(1, "sfgc", 0x00FFFF) printInline(v) syscall.devctl(1, "sfgc", 0xFFFFFF) local ok, target = pcall(syscall.readlink, fullPath) if ok then printInline(" -> ") local targetExists = pcall(syscall.stat, fullPath) - syscall.devctl(1, "sfgc", targetExists and 0xFF00FF or 0xFF0000) + syscall.devctl(1, "sfgc", targetExists and 0x00FFFF or 0xFF0000) printInline(target) syscall.devctl(1, "sfgc", 0xFFFFFF) end @@ -151,6 +153,10 @@ if cloptions.l then syscall.devctl(1, "sfgc", 0x6D00FF) printInline(v) syscall.devctl(1, "sfgc", 0xFFFFFF) + elseif isSock then + syscall.devctl(1, "sfgc", 0xFF00FF) + printInline(v) + syscall.devctl(1, "sfgc", 0xFFFFFF) else local isExec = stat and stat.perms and (math.floor(stat.perms / (2^9)) % 2 == 1) syscall.devctl(1, "sfgc", isExec and 0x00FF00 or 0xFFFFFF) @@ -175,9 +181,11 @@ for i, v in ipairs(list) do local isSym = stat and stat.etype == 0x01 if isSym then - syscall.devctl(1, "sfgc", 0xFF00FF) + syscall.devctl(1, "sfgc", 0x00FFFF) elseif isDir then syscall.devctl(1, "sfgc", 0x6D00FF) + elseif isSock then + syscall.devctl(1, "sfgc", 0xFF00FF) else local isExec = stat and stat.perms and (math.floor(stat.perms / (2^9)) % 2 == 1) syscall.devctl(1, "sfgc", isExec and 0x00FF00 or 0xFFFFFF) diff --git a/Src/install.json b/Src/install.json new file mode 100644 index 0000000..3f83663 --- /dev/null +++ b/Src/install.json @@ -0,0 +1,3 @@ +[ + "" +] \ No newline at end of file diff --git a/build.py b/build.py index 1af46c4..db21c10 100644 --- a/build.py +++ b/build.py @@ -11,6 +11,8 @@ Targets: build-mini-test build-micro-test clean + prod + prod-mini Arch flags: --arch cct @@ -32,6 +34,7 @@ PROJECT_ROOT = Path(__file__).resolve().parent SRC_ROOT = PROJECT_ROOT / "Src" TEST_ROOT = PROJECT_ROOT / "Test" BUILD_ROOT = PROJECT_ROOT / "Build" +PROD_ROOT = PROJECT_ROOT / "prod" ARCH_BOOT_DIR = { "cct": Path("boot") / "cct", @@ -46,6 +49,13 @@ def clean(): else: print("Nothing to clean.") +def cleanprod(): + if PROD_ROOT.exists(): + print(f"Removing {PROD_ROOT} ...") + shutil.rmtree(PROD_ROOT) + else: + print("Nothing to clean.") + def has_minify_header(path: Path) -> bool: try: @@ -74,9 +84,9 @@ def compress_lz4(data: bytes) -> bytes: return lz4.frame.compress(data) -def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool, arch:Union[str, None]): +def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool, arch:Union[str, None], prod:bool): print(f"Building from {src_root}") - print(f"Output to {out_root}") + print(f"Output to {out_root}") print() for pkg_dir in sorted(src_root.iterdir()): @@ -85,7 +95,8 @@ def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool, arch if pkg_dir.name[:18] == "Hyperion-firmware-": if pkg_dir.name != f"Hyperion-firmware-{arch}": - continue + if prod != True: + continue print(f"== Package: {pkg_dir.name} ==") @@ -97,8 +108,11 @@ def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool, arch if rel.name=="$PKGCONFIG.ini": continue - + dst = out_root / rel + if prod: + dst = out_root / pkg_dir.name / rel + dst.parent.mkdir(parents=True, exist_ok=True) print(f" Processing: {src.relative_to(src_root)}") @@ -132,13 +146,19 @@ def install_bootloader(arch: str, release: bool): shutil.copy2(eeprom, BUILD_ROOT / eeprom_dst_name) -def run_build(minify: bool, micro: bool, include_test: bool, arch: Union[str, None], release: bool): +def run_build(minify: bool, micro: bool, include_test: bool, arch: Union[str, None], release: bool, prod: bool): clean() BUILD_ROOT.mkdir() - + if prod: + cleanprod() + PROD_ROOT.mkdir() + out_root = BUILD_ROOT / "$" if arch else BUILD_ROOT - process_root(SRC_ROOT, out_root, minify, micro, arch) + process_root(SRC_ROOT, out_root, minify, micro, arch, False) + if prod: + process_root(SRC_ROOT, PROD_ROOT, minify, micro, arch, True) + if include_test: process_root(TEST_ROOT, out_root, minify, micro) @@ -200,9 +220,9 @@ def inject_makeusers(users, arch): def main(): parser = argparse.ArgumentParser(description="HyperionOS build script") - parser.add_argument("target", choices=["build", "build-mini", "build-micro", "build-test", "build-mini-test", "build-micro-test", "clean"]) + parser.add_argument("target", choices=["build", "build-mini", "build-micro", "build-test", "build-mini-test", "build-micro-test", "clean", "prod", "prod-mini"]) parser.add_argument("--arch", choices=["cct", "oc"], default=None, - help="Target architecture (cct or oc)") + help="Target architecture") parser.add_argument("--release", dest="release", action="store_true", default=True, help="Release build: eeprom placed as startup.lua (default)") parser.add_argument("--dev", dest="release", action="store_false", @@ -226,14 +246,15 @@ def main(): clean() return - minify = "mini" in args.target or "micro" in args.target + prod = "prod" in args.target + minify = "mini" in args.target or "micro" in args.target or "prod" in args.target micro = "micro" in args.target include_test = "test" in args.target if micro: import lz4.block - run_build(minify=minify, micro=micro, include_test=include_test, arch=args.arch, release=args.release) + run_build(minify=minify, micro=micro, include_test=include_test, arch=args.arch, release=args.release, prod=prod) if args.makeuser: print("Injecting first-boot user setup ...") diff --git a/installers/HyperionOS-install-cct.lua b/installers/HyperionOS-install-cct.lua index 30154e2..3742392 100644 --- a/installers/HyperionOS-install-cct.lua +++ b/installers/HyperionOS-install-cct.lua @@ -1,20 +1,42 @@ term.clear() +term.setTextColor(colors.white) term.setCursorPos(1,1) print("HyperionOS CCT Installer //") local w,h = term.getSize() -local install,releasename=function()end,"" -local exitall=false +local exitall,releasename,packagelist=false,"",{} -local function download(url) - local data,err=http.get(url) - if not data then error(err) end - local func,err=load(data.readAll(),"@download","t",_ENV) - if not func then error(err) end - return func() +local function printc(...) + local args={...} + for i=1, #args do + if type(args[i]) == "number" then + term.setTextColor(args[i]) + else + term.write(args[i]) + end + end + print("") end -print("Installing JSON...") -local json = download("https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/misc/cct/installdata/json") +local function download(url) + printc(colors.gray, "[ ", colors.green, " FETCH ", colors.gray, " ] ", colors.white, url) + local data,err=http.get(url) + if not data then error(err) end + local text=data.readAll() + data.close() + return text +end + +local function writeFile(path, data) + printc(colors.gray, "[ ", colors.green, "WRITING", colors.gray, " ] ", colors.white, path) + local file=fs.open(path, "w") + file.write(data) + file.close() +end + +print("Installing JSON to /hyinstall/json...") +writeFile("/hyinstall/json",download("https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/misc/json")) +print("Loading JSON...") +local json=loadfile("/hyinstall/json")() local function printTitle() term.clear() @@ -108,25 +130,16 @@ local function makePage(start, num) desc=release.body, color=release.prerelease and colors.orange or colors.white, func=function() - local data, err=http.get("https://git.astronand.dev/Hyperion/HyperionOS/raw/tag/"..release.tag_name.."/misc/cct/installcct.lua") - releasename=release.tag_name + local data=download("https://git.astronand.dev/Hyperion/HyperionOS/raw/tag/"..release.tag_name.."/Src/install.json") if not data then term.clear() term.setCursorPos(1,1) - print("Unable to install "..release.tag_name..":\n"..err) + print("Unable to find package list for ver "..release.tag_name..":\n"..err) sleep(3) return end - local func, err = load(data.readAll(), "@Installer","t",_ENV) - data.close() - if not func then - term.clear() - term.setCursorPos(1,1) - print("Unable to load Installer "..release.tag_name..":\n"..err) - sleep(3) - return - end - install=func + releasename=release.tag_name + packagelist=json.decode(data) exitall=true end } @@ -160,15 +173,10 @@ for i=5, 1, -1 do end print("") -local function printc(text, c) - term.setTextColor(c) - print(text) -end - local function delDir(dir) - printc("ls "..dir, colors.green) + printc(colors.gray, "[ ", colors.green, " LSDIR ", colors.gray, " ] ", colors.white, dir) local list=fs.list(dir) - printc("rm -rf "..dir, colors.red) + printc(colors.gray, "[ ", colors.red, " DELET ", colors.gray, " ] ", colors.white, dir) for i=1, #list do if fs.isDir(dir..list[i]) then if dir..list[i] ~= "/rom" then @@ -177,14 +185,46 @@ local function delDir(dir) end else fs.delete(dir..list[i]) - printc("rm "..dir..list[i], colors.orange) + printc(colors.gray, "[ ", colors.red, " DELET ", colors.gray, " ] ", colors.white, dir..list[i]) end - sleep(.01) + sleep(.1) end end delDir("/") -term.clear() -term.setCursorPos(1,1) -term.setTextColor(colors.white) -install(releasename) \ No newline at end of file + +print("") +printc(colors.cyan, " \\\\Installing//") +print("") +printc(colors.white, "Getting package list...") +local list=json.decode() + +local function installdir(path, dir, pkg) + local data=json.decode(download("https://git.astronand.dev/api/v1/repos/Hyperion/HyperionOS/contents/prod/"..pkg..dir.."?ref="..releasename)) + if not data then error("Uh Oh: JSON decode error...") end + for i=1, #data do + local entry=data[i] + if entry.type == "dir" then + installdir(path, dir..entry.name.."/", pkg) + elseif entry.type == "file" then + writeFile(path..dir..entry.name, download(entry.download_url)) + else + error("Uh Oh: unknown entrytype "..entry.path) + end + end +end + +local function installpkg(pkg) + installdir("/$", "/", pkg) +end + +for i=1, #packagelist do + installpkg(packagelist[i]) +end + +installpkg("Hyperion-firmware-cct") +fs.copy("/$/boot/cct/eeprom", "/startup.lua") + +printc(colors.white, "Rebooting...") +sleep(1) +os.reboot() \ No newline at end of file diff --git a/misc/cct/installcct.lua b/misc/cct/installcct.lua deleted file mode 100644 index 2974f27..0000000 --- a/misc/cct/installcct.lua +++ /dev/null @@ -1,21 +0,0 @@ -local release=... -term.clear() -term.setCursorPos(1,1) -print("Hello, World!") -print("Installing tar but bad...") -shell.run("wget https://git.astronand.dev/Hyperion/HyperionOS/raw/tag/"..release.."/misc/cct/installdata/tarbad /tar.lua") -print("Installing HyperionOS...") -print("Installing precompiled tar") -shell.run("wget https://git.astronand.dev/Hyperion/HyperionOS/raw/tag/"..release.."/misc/cct/installdata/Build.tar /Build.tar") -shell.run("tar Build.tar /") -sleep(1) -print("Removing tar but bad...") -shell.run("rm /tar.lua") -shell.run("rm $") -shell.run("rm Build.tar") -shell.run("cp Build $") -shell.run("rm Build") -fs.copy("/$/boot/cct/eeprom","/startup.lua") -print("Installing...") -sleep(1) -dofile("startup.lua") \ No newline at end of file diff --git a/misc/cct/installdata/Build.tar b/misc/cct/installdata/Build.tar deleted file mode 100644 index cf13e58..0000000 Binary files a/misc/cct/installdata/Build.tar and /dev/null differ diff --git a/misc/cct/installdata/tarbad b/misc/cct/installdata/tarbad deleted file mode 100644 index caa6983..0000000 --- a/misc/cct/installdata/tarbad +++ /dev/null @@ -1,157 +0,0 @@ - -local function octal_to_number(str) - str = str:gsub("%z", ""):match("^%s*(.-)%s*$") - return tonumber(str, 8) or 0 -end - -local function dedupe_path(path) - - local parts = {} - for p in path:gmatch("[^/]+") do table.insert(parts, p) end - - for prefix_len = 1, math.floor(#parts / 2) do - local ok = true - for i = 1, prefix_len do - if parts[i] ~= parts[i + prefix_len] then - ok = false - break - end - end - if ok then - local cleaned = {} - for i = 1, #parts - prefix_len do - cleaned[#cleaned + 1] = parts[i + prefix_len] - end - return table.concat(cleaned, "/") - end - end - - return path -end - - -local function make_dirs(root, path) - local cur = root - for part in path:gmatch("([^/]+)/") do - if not cur[part] then - cur[part] = { __type = "dir", __entries = {} } - end - cur = cur[part].__entries - end - return cur -end - -local function flatten(node, prefix) - local out = {} - prefix = prefix or "" - - for name, obj in pairs(node) do - local full = prefix .. name - if obj.__type == "file" then - out[#out+1] = { - name = full, - type = "file", - contents = obj.__contents - } - elseif obj.__type == "dir" then - out[#out+1] = { - name = full .. "/", - type = "dir", - contents = flatten(obj.__entries, full .. "/") - } - end - end - - return out -end - -local function unpack_tar(tarstr) - local i = 1 - local len = #tarstr - local root = {} - - while i + 512 <= len do - local header = tarstr:sub(i, i + 511) - - if header:match("^\0+$") then break end - - local name_raw = header:sub(1, 100):gsub("%z.*", "") - local prefix_raw = header:sub(346, 500):gsub("%z.*", "") - - local name - if prefix_raw ~= "" then - name = prefix_raw .. "/" .. name_raw - else - name = name_raw - end - - name = name:gsub("^%./", ""):gsub("/+", "/") - - name = dedupe_path(name) - - local size = octal_to_number(header:sub(125,136)) - local typeflag = header:sub(157,157) - - i = i + 512 - - local contents = tarstr:sub(i, i + size - 1) - local pad = (512 - (size % 512)) % 512 - i = i + size + pad - - if name == "" then goto continue end - - local is_dir = typeflag == "5" or name:sub(-1) == "/" - - local clean_name = name:gsub("/$", "") - if clean_name == "" then goto continue end - - local parent_path = clean_name:match("(.+)/") - local fname = clean_name:match("([^/]+)$") - if not fname then goto continue end - - local parent = root - if parent_path then - parent = make_dirs(root, parent_path .. "/") - end - - if is_dir then - parent[fname] = parent[fname] or { __type = "dir", __entries = {} } - else - parent[fname] = { __type = "file", __contents = contents } - end - - ::continue:: - end - - return flatten(root) -end - -local function write_directory(prefix, items) - for _, v in ipairs(items) do - if v.type == "dir" then - fs.makeDir(prefix..v.name) - write_directory(prefix, v.contents) - elseif v.type == "file" then - local file = fs.open(prefix..v.name, "w") - file.write(v.contents) - file.close() - end - end -end - -local in_tar = ({...})[1] -local out_dir = ({...})[2] - -if not in_tar or not out_dir then - print("Usage: unpack_tar ") - return -end - -local f = fs.open(in_tar, "r") -local tarstr = f.readAll() -f.close() - -local list = unpack_tar(tarstr) -write_directory(out_dir, list) - -print("TAR extracted into: " .. out_dir) diff --git a/misc/cct/installdata/json b/misc/json similarity index 100% rename from misc/cct/installdata/json rename to misc/json diff --git a/prod/Hyperion-core/lib/colors b/prod/Hyperion-core/lib/colors new file mode 100644 index 0000000..c8a00cd --- /dev/null +++ b/prod/Hyperion-core/lib/colors @@ -0,0 +1 @@ +return{white=0xFFFFFF,red=0xFF0000,green=0x00FF00,blue=0x0000FF,cyan=0x00FFFF,yellow=0xFFFF00,purple=0xFF00FF,black=0x000000,gray=0x888888,lightgrey=0xBBBBBB,darkgrey=0x444444,orange=0xFF8800,mint=0x00FF88,brown=0xa52a2a,chocolate=0xd2691e} diff --git a/prod/Hyperion-core/lib/fs b/prod/Hyperion-core/lib/fs new file mode 100644 index 0000000..5268349 --- /dev/null +++ b/prod/Hyperion-core/lib/fs @@ -0,0 +1 @@ +local a={}function a.open(b,c)local d=syscall.open(b,c)local e={close=function()return syscall.close(d)end,flush=function()syscall.fsync(d)end}if c=="r"then e.read=function(f)local g=syscall.read(d,f)return g end;e.readAll=function(h)local i={}while true do local j=syscall.read(d,h or 65536)if j==nil or#j==0 then break end;table.insert(i,j)end;return table.concat(i)end;e.readLine=function(h)local k={}local l=""local m=h or 65536;local n=false;while true do local o=l:find("\n")if o then local p=l:sub(1,o-1)l=l:sub(o+1)return p end;if n then if l~=""then local q=l;l=""return q else return nil end end;local j=syscall.read(d,m)if not j or j==""then n=true else l=l..j end end end elseif c=="w"then e.write=function(g)return syscall.write(d,g)end elseif c=="a"then e.write=function(g)return syscall.write(d,g)end else error("Invalid mode '"..c.."'",2)end;return e end;function a.readAllText(b)local r=a.open(b,"r")if not r then return false end;local s=r.readAll()r.close()return s end;function a.writeAllText(b,g)local r=a.open(b,"w")r.write(g)r.close()end;function a.appendAllText(b,g)local r=a.open(b,"a")if not r then return false end;r.write(g)r.close()end;function a.mkdir(b)return syscall.mkdir(b)end;function a.remove(b)return syscall.remove(b)end;function a.list(b)return syscall.listdir(b)end;function a.type(b)return syscall.type(b)end;function a.stat(b)return syscall.stat(b)end;function a.exists(b)return syscall.exists(b)end;function a.getcwd()return syscall.getcwd()end;function a.chdir(b)return syscall.chdir(b)end;function a.isDir(b)return syscall.type(b)=="directory"end;return a diff --git a/Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/40_modem.kmod b/prod/Hyperion-core/lib/http similarity index 100% rename from Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/40_modem.kmod rename to prod/Hyperion-core/lib/http diff --git a/prod/Hyperion-core/lib/io b/prod/Hyperion-core/lib/io new file mode 100644 index 0000000..e0eb470 --- /dev/null +++ b/prod/Hyperion-core/lib/io @@ -0,0 +1,6 @@ +local io = {} +local fs = require("fs") + +function io.open(path, mode) + return fs.open(path, mode) +end \ No newline at end of file diff --git a/prod/Hyperion-firmware-ac/boot/ac/boot.lua b/prod/Hyperion-firmware-ac/boot/ac/boot.lua new file mode 100644 index 0000000..9b7a5fa --- /dev/null +++ b/prod/Hyperion-firmware-ac/boot/ac/boot.lua @@ -0,0 +1 @@ +local a={...}local b=a[1]local c=components:getFirst("gpu")local d=nil;local e,f=0,0;local g,h=128,25;if c then d=c:newBuffer(g,h)for i,j in components:list()do if i=="screen"then c:assignBuffer(d,j)end end end;local function k(l)e,f=d:pasteText(e,f,"SCROLL_SPILL_CLEAR",l)f=f+1;e=0;if f>=h then f=h-1;d:newline()end end;local function m(n)c:freeAllBuffers()d=c:newBuffer(g,h)for i,j in components:list()do if i=="screen"then c:assignBuffer(d,j)end end;term.setBackgroundColor(0x1)term.setTextColor(0x4)term.clear()term.setCursorPos(1,1)term.write("A critical error occurred while loading the system:")term.setCursorPos(1,3)k(n)while true do end end;local o,n=xpcall(function()local p={}local q={coroutine=true,debug=true,_VERSION=true,assert=true,collectgarbage=true,error=true,gcinfo=true,getmetatable=true,ipairs=true,__inext=true,load=true,math=true,next=true,pairs=true,pcall=true,rawequal=true,rawget=true,rawlen=true,rawset=true,select=true,setmetatable=true,string=true,table=true,tonumber=true,tostring=true,type=true,xpcall=true,_G=true}local debug=debug;for r,j in pairs(_G)do if not q[r]or q[r]==nil then p[r]=j;_G[r]=nil end end;local function s(t)local u=t:read()local v={u or""}local w=1;local x=false;local function y()return table.concat(v)end;local function z(A)v={A}end;local function B()t.write(y())end;local t={}function t:read(C)assert(not x,"file is closed")local A=y()local D=#A;if not C then local E=A:sub(w)w=D+1;return E end;local E=A:sub(w,w+C-1)w=w+#E;return E end;function t:write(F)assert(not x,"file is closed")local A=y()local G=A:sub(1,w-1)local H=A:sub(w+#F)z(G..F..H)w=w+#F;return true end;function t:seek(I,J)assert(not x,"file is closed")local A=y()local D=#A;I=I or"cur"J=J or 0;if I=="set"then w=J+1 elseif I=="cur"then w=w+J elseif I=="end"then w=D+J+1 else error("invalid whence")end;if w<1 then w=1 end;if w>D+1 then w=D+1 end;return w-1 end;function t:close()assert(not x,"file is closed")B()x=true end;function t:flush()assert(not x,"file is closed")B()end;return t end;local function K(L)local t=b:open(L,"r")if not t then m("Could not open file: "..L)end;local y=t:read()return y end;local M=load(K("/boot/kernel.lua"),"@Kernel")local N=load(K("/boot/ac/initdisks"),"@Init_disks")(p)local O=load(K("/boot/initfs"),"@InitFs")()if not M then m("Could not load kernel.")end;if not N then m("Could not load initdisks.")end;if not O then m("Could not load initfs.")end;local P=p.components:getFirst("computer")local Q=p.components:getFirst("uefi")local R={time=function()return p.os.epoch("utc")end,clock=function()return p.os.clock()*1000 end,shutdown=p.os.shutdown,reboot=p.os.reboot,getMachineEvent=function()return P:getMachineEvent()end,getEEPROM=function()return Q.data end,setEEPROM=function(S,l)Q.data=l end}local T={[0x1]=1,[0x2]=2,[0x4]=3,[0x8]=4,[0x10]=5,[0x20]=6,[0x40]=7,[0x80]=8,[0x100]=9,[0x200]=10,[0x400]=11,[0x800]=12,[0x1000]=13,[0x2000]=14,[0x4000]=15,[0x8000]=16}local U={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000}p.term.setBackgroundColor(0x8000)p.term.setTextColor(0x1000)p.term.clear()p.term.setCursorPos(1,1)local V=coroutine.create(function()local o,n=xpcall(M,debug.traceback,p,N,"cct","/sbin/init",{print=function(S,l)k(l.."\n")end,printInline=function(S,l)k(l)end,clear=function()p.term.clear()p.term.setCursorPos(1,1)end,setCursorPos=function(S,W,X)p.term.setCursorPos(W,X)end,getCursorPos=function()return p.term.getCursorPos()end,getSize=function()return p.term.getSize()end,setBackgroundColor=function(S,Y)p.term.setBackgroundColor(U[Y])end,setTextColor=function(S,Y)p.term.setTextColor(U[Y])end,getBackgroundColor=function()return T[p.term.getBackgroundColor()]end,getTextColor=function()return T[p.term.getTextColor()]end},R,O,"$")if not o then m(n)end end)function coroutine.resumeWithTimeout(Z,_,...)local a0=R.time()debug.sethook(Z,function()if R.time()>a0+_ then return coroutine.yield("timeout")end end,"",1000)local a1={coroutine.resume(Z,...)}if a1[1]and a1[2]=="timeout"then return"timeout"elseif a1[1]==false then return"error",a1[2]else debug.sethook(Z)return"success",table.unpack(a1,2)end end;k("Loaded in "..tostring(p.os.clock()).." seconds.\n")while true do local a2,n=coroutine.resumeWithTimeout(V,50)p.os.queueEvent("NoSleep")local a3=false;while not a3 do local a4={coroutine.yield()}if a4[1]=="key"then queueEvent("keyPressed",1,a4[2])if acekeys[a4[2]]then queueEvent("keyTyped",1,acekeys[a4[2]])end elseif a4[1]=="char"then queueEvent("keyTyped",1,a4[2])elseif a4[1]=="key_up"then queueEvent("keyReleased",1,a4[2])elseif a4[1]=="disk"then queueEvent("componentAdded","disk")elseif a4[1]=="disk_eject"then queueEvent("componentRemoved","disk")elseif a4[1]=="modem_message"then queueEvent("modem_message",table.unpack(a4,2))elseif a4[1]=="rednet_message"then queueEvent("rednet_message",table.unpack(a4,2))elseif a4[1]=="http_success"then queueEvent("http_success",table.unpack(a4,2))elseif a4[1]=="http_failure"then queueEvent("http_failure",table.unpack(a4,2))elseif a4[1]=="NoSleep"then a3=true end end;if a2=="error"or coroutine.status(V)=="dead"then m("Kernel error: "..tostring(n))coroutine.yield("key")end end end,debug.traceback)if not o then m("Fatal error during boot: "..n)end;while true do coroutine.yield()end diff --git a/prod/Hyperion-firmware-ccpc/boot/ccpc/boot.lua b/prod/Hyperion-firmware-ccpc/boot/ccpc/boot.lua new file mode 100644 index 0000000..6c67bfb --- /dev/null +++ b/prod/Hyperion-firmware-ccpc/boot/ccpc/boot.lua @@ -0,0 +1 @@ +local a=({...})[1]or"/$"local term=term;local os=os;local function b(c)local d,e=term.getCursorPos()local f,g=term.getSize()for h=1,#c do local i=c:sub(h,h)if i=="\n"then e=e+1;d=1 elseif i=="\t"then local j=4;local k=j-(d-1)%j;term.write(string.rep(" ",k))d=d+k elseif i=="\b"then if d>1 then d=d-1;term.setCursorPos(d,e)term.write(" ")term.setCursorPos(d,e)end else if d<=f and e<=g then term.setCursorPos(d,e)term.write(i)d=d+1 end end;if d>f then d=1;e=e+1 end;if e-1>=g then term.scroll(1)e=g;term.setCursorPos(d,e)end end;term.setCursorPos(d,e)end;local function l(m)term.setBackgroundColor(0x1)term.setTextColor(0x4)term.clear()term.setCursorPos(1,1)term.write("A critical error occurred while loading the system:")term.setCursorPos(1,3)b(m)while true do end end;term.setCursorBlink(false)local n,m=xpcall(function()local o={BOOT_DRIVE_PATH=a}local p={coroutine=true,debug=true,_VERSION=true,assert=true,collectgarbage=true,error=true,gcinfo=true,getmetatable=true,ipairs=true,__inext=true,load=true,math=true,next=true,pairs=true,pcall=true,rawequal=true,rawget=true,rawlen=true,rawset=true,select=true,setmetatable=true,string=true,table=true,tonumber=true,tostring=true,type=true,xpcall=true,_G=true}local debug=debug;for h,q in pairs(_G)do if not p[h]or p[h]==nil then o[h]=q;_G[h]=nil end end;local r={[o.keys.enter]="\n",[o.keys.tab]="\t",[o.keys.backspace]="\b",[o.keys.up]="\17",[o.keys.down]="\18",[o.keys.left]="\19",[o.keys.right]="\20"}function sleep(s)local t=o.os.clock()+s;while t>o.os.clock()do end end;o.term.setPaletteColor(0x1,0xFFFFFF)o.term.setPaletteColor(0x2,0xFF0000)o.term.setPaletteColor(0x4,0x00FF00)o.term.setPaletteColor(0x8,0x0000FF)o.term.setPaletteColor(0x10,0x00FFFF)o.term.setPaletteColor(0x20,0xFF00FF)o.term.setPaletteColor(0x40,0xFFFF00)o.term.setPaletteColor(0x80,0xFF6D00)o.term.setPaletteColor(0x100,0x6DFF55)o.term.setPaletteColor(0x200,0x24FFFF)o.term.setPaletteColor(0x400,0x924900)o.term.setPaletteColor(0x800,0x6D6D55)o.term.setPaletteColor(0x1000,0xDBDBAA)o.term.setPaletteColor(0x2000,0x6D00FF)o.term.setPaletteColor(0x4000,0xB6FF00)o.term.setPaletteColor(0x8000,0x000000)local function u(v)local w=o.fs.open(v,"r")if not w then l("Could not open file: "..v)end;local x=w.readAll()w.close()return x end;local y=load(u(a.."/boot/kernel.lua"),"@Kernel")local z=load(u(a.."/boot/cct/initdisks"),"@Init_disks")(o)local A=load(u(a.."/boot/initfs"),"@InitFs")()if not y then l("Could not load kernel.")end;if not z then l("Could not load initdisks.")end;if not A then l("Could not load initfs.")end;if not o.fs.exists("/nvram.dat")then local w=o.fs.open("/nvram.dat","w")w.write("Hello, World!")w.close()end;local B;if o.fs.exists("/startup.lua")then B="/startup.lua"elseif o.fs.exists("/eeprom")then B="/eeprom"end;local C={}local function D(E,...)table.insert(C,{E,...})end;local F={[0x000000]=0x0001,[0xFFFFFF]=0x0002,[0xFF0000]=0x0004,[0x00FF00]=0x0008,[0x0000FF]=0x0010,[0x00FFFF]=0x0020,[0xFF00FF]=0x0040,[0xFFFF00]=0x0080,[0xFF6D00]=0x0100,[0x6DFF55]=0x0200,[0x24FFFF]=0x0400,[0x924900]=0x0800,[0x6D6D55]=0x1000,[0xDBDBAA]=0x2000,[0x6D00FF]=0x4000,[0xB6FF00]=0x8000}local G,H=0x6D6D55,0x000000;local I,J,K,L={},{},{},0;local function M(N,O)local P=nil;local Q=math.huge;for R,S in pairs(N)do local T=math.abs(R-O)if T=16 then K[V]=J[V]J[V]=nil;I[V]=nil;return K[V]end;return J[V]end;local W=M(F,V)if not W then return nil end;local X=F[W]J[V]=X;I[V]=1;return X end;local Y={getEpochMs=function()return o.os.epoch("utc")end,getUptime=function()return o.os.clock()*1000 end,date=function()return o.os.date("!%Y-%m-%dT%H:%M:%SZ",o.os.epoch("utc")/1000)end,getMachineEvent=function()if#C>0 then return table.unpack(table.remove(C,1))else return nil end end,getEEPROM=function()return u(B)end,setEEPROM=function(S,c)local g=o.fs.open(B,"w")g.write(c)g.close()end,initfs=A,disks=z,screenCtl={print=function(S,c)b(c.."\n")end,printInline=function(S,c)b(c)end,clear=function()o.term.clear()o.term.setCursorPos(1,1)end,setCursorPos=function(S,d,e)o.term.setCursorPos(d,e)end,getCursorPos=function()return o.term.getCursorPos()end,getSize=function()return o.term.getSize()end,setBackgroundColor=function(S,Z)o.term.setBackgroundColor(U(Z))end,setTextColor=function(S,Z)o.term.setTextColor(U(Z))end,getBackgroundColor=function()return H end,getTextColor=function()return G end,enable=function()end,disable=function()end},architecture="cct",getNvram=function()return u("/nvram.dat")end,setNvram=function(S,c)local g=o.fs.open("/nvram.dat","w")g.write(c)g.close()end,firmware=o,reboot=false}o.term.setBackgroundColor(0x8000)o.term.setTextColor(0x1000)o.term.clear()o.term.setCursorPos(1,1)local _=coroutine.create(function()local n,m=xpcall(y,debug.traceback,Y)if not n and not Y.reboot then l(m)end;if m then o.os.reboot()else o.os.shutdown()end end)function coroutine.resumeWithTimeout(a0,a1,...)local a2=Y.getEpochMs()debug.sethook(a0,function()if Y.getEpochMs()>a2+a1 then return coroutine.yield("timeout")end end,"",1000)local a3={coroutine.resume(a0,...)}if a3[1]and a3[2]=="timeout"then return"timeout"elseif a3[1]==false then return"error",a3[2]else debug.sethook(a0)return"success",table.unpack(a3,2)end end;b("Loaded in "..tostring(o.os.clock()).." seconds.\n")while true do local a4,m=coroutine.resumeWithTimeout(_,50)o.os.queueEvent("NoSleep")local a5=false;while not a5 do local E={coroutine.yield()}if E[1]=="key"then D("keyPressed",1,E[2])if r[E[2]]then D("keyTyped",1,r[E[2]])end elseif E[1]=="char"then D("keyTyped",1,E[2])elseif E[1]=="key_up"then D("keyReleased",1,E[2])elseif E[1]=="disk"then D("componentAdded","disk")elseif E[1]=="disk_eject"then D("componentRemoved","disk")elseif E[1]=="modem_message"then D("modem_message",table.unpack(E,2))elseif E[1]=="rednet_message"then D("rednet_message",table.unpack(E,2))elseif E[1]=="http_success"then D("http_success",table.unpack(E,2))elseif E[1]=="http_failure"then D("http_failure",table.unpack(E,2))elseif E[1]=="NoSleep"then a5=true end end;if a4=="error"or coroutine.status(_)=="dead"then if Y.reboot then o.os.reboot()end;l("Kernel error: "..tostring(m))coroutine.yield("key")end;z:refresh()end end,debug.traceback)if not n then l("Fatal error during boot: "..m)end;while true do coroutine.yield("key")end diff --git a/prod/Hyperion-firmware-ccpc/boot/ccpc/eeprom b/prod/Hyperion-firmware-ccpc/boot/ccpc/eeprom new file mode 100644 index 0000000..9bba429 --- /dev/null +++ b/prod/Hyperion-firmware-ccpc/boot/ccpc/eeprom @@ -0,0 +1 @@ +local a=({...})[1]or"/$"local b={...}local c={keys=true,bit32=true,bit=true,ccemux=true,config=true,coroutine=true,debug=true,fs=true,http=true,mounter=true,os=true,periphemu=true,peripheral=true,redstone=true,rs=true,term=true,utf8=true,_HOST=true,_CC_DEFAULT_SETTINGS=true,_CC_DISABLE_LUA51_FEATURES=true,_VERSION=true,assert=true,collectgarbage=true,error=true,gcinfo=true,getfenv=true,getmetatable=true,ipairs=true,__inext=true,load=true,loadstring=true,math=true,newproxy=true,next=true,pairs=true,pcall=true,rawequal=true,rawget=true,rawlen=true,rawset=true,select=true,setfenv=true,setmetatable=true,string=true,table=true,tonumber=true,tostring=true,type=true,unpack=true,xpcall=true,turtle=true,pocket=true,commands=true,_G=true}local d={}for e in pairs(_G)do if not c[e]then table.insert(d,e)end end;for f,e in ipairs(d)do _G[e]=nil end;local g=_G.term.native()for f,h in ipairs{"nativePaletteColor","nativePaletteColour","screenshot"}do g[h]=_G.term[h]end;_G.term=g;if _G.http then _G.http.checkURL=_G.http.checkURLAsync;_G.http.websocket=_G.http.websocketAsync end;if _G.commands then _G.commands=_G.commands.native end;if _G.turtle then _G.turtle.native,_G.turtle.craft=nil end;local i={os={"version","pullEventRaw","pullEvent","run","loadAPI","unloadAPI","sleep"},http=_G.http and{"get","post","put","delete","patch","options","head","trace","listen","checkURLAsync","websocketAsync"},fs={"complete","isDriveRoot"}}for e,j in pairs(i)do for f,k in ipairs(j)do _G[e][k]=nil end end;local l=error;_G.error=function()end;_G.term.redirect=function()end;function _G.term.native()_G.term.native=nil;_G.term.redirect=nil;_G.error=l;term.setBackgroundColor(32768)term.setTextColor(1)term.setCursorPos(1,1)term.setCursorBlink(true)term.clear()local m=fs.open(a.."/boot/cct/boot.lua","r")if m==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;local n,o=loadstring(m.readAll(),"@bootloader")m.close()if n==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write(o)term.setCursorPos(1,3)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;setfenv(n,_G)local p=os.shutdown;os.shutdown=function()os.shutdown=p;return n(a)end end;if debug then local function q(r,s,t,u)local v,w,x=1,debug.getupvalue(r[s],u)while w~=t and w~=nil do w,x=debug.getupvalue(r[s],v)v=v+1 end;r[s]=x or r[s]end;q(_G,"loadstring","nativeloadstring",1)q(_G,"load","nativeload",5)if http then q(http,"request","nativeHTTPRequest",3)end;q(os,"shutdown","nativeShutdown",1)q(os,"reboot","nativeReboot",1)if turtle then q(turtle,"equipLeft","v",1)q(turtle,"equipRight","v",1)end;do local v,w,x=1,debug.getupvalue(peripheral.isPresent,2)while w~="native"and w~=nil do w,x=debug.getupvalue(peripheral.isPresent,v)v=v+1 end;_G.peripheral=x or peripheral end end diff --git a/prod/Hyperion-firmware-ccpc/boot/ccpc/initdisks b/prod/Hyperion-firmware-ccpc/boot/ccpc/initdisks new file mode 100644 index 0000000..dc41dfd --- /dev/null +++ b/prod/Hyperion-firmware-ccpc/boot/ccpc/initdisks @@ -0,0 +1 @@ +local a=({...})[1]local b=a.BOOT_DRIVE_PATH;local c=a.fs;local d=a.peripheral;local e={}local f={"top","bottom","left","right","front","back"}function e.getNames()local g={}for h=1,#f do local i=f[h]if d.isPresent(i)then table.insert(g,i)if d.hasType(i,"peripheral_hub")then local j=d.call(i,"getNamesRemote")for k,l in ipairs(j)do table.insert(g,l)end end end end;return g end;function e.isPresent(l)if d.isPresent(l)then return true end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return true end end;return false end;function e.getType(e)if type(e)=="string"then if d.isPresent(e)then return d.getType(e)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"getTypeRemote",e)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(m.types)end end;function e.hasType(e,n)if type(e)=="string"then if d.isPresent(e)then return d.hasType(e,n)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"hasTypeRemote",e,n)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return m.types[n]~=nil end end;function e.getMethods(l)if d.isPresent(l)then return d.getMethods(l)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"getMethodsRemote",l)end end;return nil end;function e.getName(e)local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return m.name end;function e.call(l,o,...)if d.isPresent(l)then return d.call(l,o,...)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"callRemote",l,o,...)end end;return nil end;function e.wrap(l)local p=e.getMethods(l)if not p then return nil end;local q={e.getType(l)}for r=1,#q do q[q[r]]=true end;local s=setmetatable({},{__name="peripheral",name=l,type=q[1],types=q})for k,o in ipairs(p)do s[o]=function(...)return e.call(l,o,...)end end;return s end;function e.find(t,u)local g={}for k,l in ipairs(e.getNames())do if e.hasType(l,t)then local v=e.wrap(l)if u==nil or u(l,v)then table.insert(g,v)end end end;return table.unpack(g)end;local w={}local x={}local function y(z)if not z or z==""then return"/"end;return c.combine("/",z)end;local function A(B,C,D,E)C=y(C)local F={address=B,isReadOnly=function()return D end}function F:spaceUsed()return c.getCapacity(C)-c.getFreeSpace(C)end;function F:spaceTotal()return c.getCapacity(C)end;function F:list(z)local G=c.combine(C,z)if not c.exists(G)or not c.isDir(G)then return nil,"not directory"end;return c.list(G)end;function F:fileExists(z)local G=c.combine(C,z)return c.exists(G)and not c.isDir(G)end;function F:directoryExists(z)local G=c.combine(C,z)return c.exists(G)and c.isDir(G)end;function F:type(z)local G=c.combine(C,z)if not c.exists(G)then return nil elseif c.isDir(G)then return"directory"else return"file"end end;function F:makeDirectory(z)local G=c.combine(C,z)c.makeDir(G)return true end;function F:remove(z)local G=c.combine(C,z)if c.exists(G)then c.delete(G)end;return true end;function F:setLabel(H)E.setLabel(H)end;function F:getLabel(H)return E.getLabel()end;function F:attributes(z)local G=c.combine(C,z)return c.attributes(G)end;function F:open(z,I)local G=c.combine(C,z)return c.open(G,I)end;return F end;x["$"]=A("$",b,false,{setLabel=function(H)local J=c.open("/.label","w")J.write(H)J.close()end,getLabel=function()local J=c.open("/.label","r")if not J then return"$"end;local H=J.readAll()J.close()return H end})x["rom"]=A("rom","/rom",true,{setLabel=function(H)error("Device is read-only")end,getLabel=function()return"cctrom"end})local function K()w={}for k,F in ipairs({e.find("drive")})do if F.isDiskPresent()then w[tostring(F.getDiskID())]=A("cctdisk"..tostring(F.getDiskID()),F.getMountPath(),false,c)end end end;local function L()K()local M={}for B,N in pairs(x)do M[B]=N end;for B,N in pairs(w)do M[B]=N end;return pairs(M)end;return{refresh=K,list=L} diff --git a/prod/Hyperion-firmware-ccpc/lib/modules/ccpc/25_gfx.kmod b/prod/Hyperion-firmware-ccpc/lib/modules/ccpc/25_gfx.kmod new file mode 100644 index 0000000..4b3a2db --- /dev/null +++ b/prod/Hyperion-firmware-ccpc/lib/modules/ccpc/25_gfx.kmod @@ -0,0 +1 @@ +local a=...local b=a.apis;local c=b.peripheral;local d={"top","bottom","left","right","front","back"}local e={}function e.getNames()local f={}for g=1,#d do local h=d[g]if c.isPresent(h)then table.insert(f,h)if c.hasType(h,"peripheral_hub")then local i=c.call(h,"getNamesRemote")for j,k in ipairs(i)do table.insert(f,k)end end end end;return f end;function e.isPresent(k)if c.isPresent(k)then return true end;for g=1,#d do local h=d[g]if c.hasType(h,"peripheral_hub")and c.call(h,"isPresentRemote",k)then return true end end;return false end;function e.getType(e)if type(e)=="string"then if c.isPresent(e)then return c.getType(e)end;for g=1,#d do local h=d[g]if c.hasType(h,"peripheral_hub")and c.call(h,"isPresentRemote",e)then return c.call(h,"getTypeRemote",e)end end;return nil else local l=getmetatable(e)if not l or l.__name~="peripheral"or type(l.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(l.types)end end;function e.hasType(e,m)if type(e)=="string"then if c.isPresent(e)then return c.hasType(e,m)end;for g=1,#d do local h=d[g]if c.hasType(h,"peripheral_hub")and c.call(h,"isPresentRemote",e)then return c.call(h,"hasTypeRemote",e,m)end end;return nil else local l=getmetatable(e)if not l or l.__name~="peripheral"or type(l.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return l.types[m]~=nil end end;function e.getMethods(k)if c.isPresent(k)then return c.getMethods(k)end;for g=1,#d do local h=d[g]if c.hasType(h,"peripheral_hub")and c.call(h,"isPresentRemote",k)then return c.call(h,"getMethodsRemote",k)end end;return nil end;function e.getName(e)local l=getmetatable(e)if not l or l.__name~="peripheral"or type(l.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return l.name end;function e.call(k,n,...)if c.isPresent(k)then return c.call(k,n,...)end;for g=1,#d do local h=d[g]if c.hasType(h,"peripheral_hub")and c.call(h,"isPresentRemote",k)then return c.call(h,"callRemote",k,n,...)end end;return nil end;function e.wrap(k)local o=e.getMethods(k)if not o then return nil end;local p={e.getType(k)}for q=1,#p do p[p[q]]=true end;local r=setmetatable({},{__name="peripheral",name=k,type=p[1],types=p})for j,n in ipairs(o)do r[n]=function(...)return e.call(k,n,...)end end;return r end;function e.find(s,t)local f={}for j,k in ipairs(e.getNames())do if e.hasType(k,s)then local u=e.wrap(k)if t==nil or t(k,u)then table.insert(f,u)end end end;return table.unpack(f)end;local v={[0x1]=1,[0x2]=2,[0x4]=3,[0x8]=4,[0x10]=5,[0x20]=6,[0x40]=7,[0x80]=8,[0x100]=9,[0x200]=10,[0x400]=11,[0x800]=12,[0x1000]=13,[0x2000]=14,[0x4000]=15,[0x8000]=16}local w={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000}local function x(y,z)local A,B=z.getCursorPos()local C,D=z.getSize()for q=1,#y do local E=y:sub(q,q)if E=="\n"then B=B+1;A=1 elseif E=="\t"then local F=4;local G=F-(A-1)%F;z.write(string.rep(" ",G))A=A+G elseif E=="\b"then if A>1 then A=A-1;z.setCursorPos(A,B)z.write(" ")z.setCursorPos(A,B)end else if A<=C and B<=D then z.setCursorPos(A,B)z.write(E)A=A+1 end end;if A>C then A=1;B=B+1 end;if B-1>=D then z.scroll(1)B=D;z.setCursorPos(A,B)end end;z.setCursorPos(A,B)end;a.devfs.data.tty={}local H,I=false,false;local function J(K)if K then return"T"else return"F"end end;local function L(M,N,O)a.devfs.data["tty"][N]=function(P,Q)if P=="type"then return"character device"elseif P=="open"then local D={read=function(R)local S=""for q=1,R or 1 do local T={O()}if T[1]then S=S..T[1]end end;if S==""then S=nil end;return S end,write=function(U)x(U,M)end,size=function()local V={M.getSize()}return table.concat(V,";")end,clear=function()M.clear()M.setCursorPos(1,1)end,gpos=function()local V={M.getCursorPos()}return table.concat(V,";")end,spos=function(A,B)return M.setCursorPos(A,B)end,sfgc=function(E)return M.setTextColor(w[E])end,sbgc=function(E)return M.setBackgroundColor(w[E])end,gfgc=function()return v[M.getTextColor()]end,gbgc=function()return v[M.getBackgroundColor()]end,gctrl=function()return J(H)..";"..J(I)end}if Q=="rw"then return D elseif Q=="r"then D["write"]=nil;return D elseif Q=="w"then D["read"]=nil;return D end end end end;local W=a.newFifo()a.processes.cctmond=function()local X=false;while true do local T={a.EFI:getMachineEvent()}if T[1]then local Y=T[1]local Z=T[3]local _={[b.keys.a]=1,[b.keys.b]=2,[b.keys.c]=3,[b.keys.d]=4,[b.keys.e]=5,[b.keys.f]=6,[b.keys.g]=7,[b.keys.h]=8,[b.keys.i]=9,[b.keys.j]=10,[b.keys.k]=11,[b.keys.l]=12,[b.keys.m]=13,[b.keys.n]=14,[b.keys.o]=15,[b.keys.p]=16,[b.keys.q]=17,[b.keys.r]=18,[b.keys.s]=19,[b.keys.t]=20,[b.keys.u]=21,[b.keys.v]=22,[b.keys.w]=23,[b.keys.x]=24,[b.keys.y]=25,[b.keys.z]=26}if Y=="keyPressed"then if Z==b.keys.leftCtrl or Z==b.keys.rightCtrl then H=true elseif Z==b.keys.leftAlt or Z==b.keys.rightAlt then I=true end;if H then local a0=_[Z]if a0 then if a0==3 then for j,a1 in ipairs(syscall.getTasks())do syscall.sigsend(a1,1)end else W.push(string.char(a0))end end else local a2={[b.keys.up]="",[b.keys.down]="",[b.keys.right]="",[b.keys.left]="",[b.keys.home]="",[b.keys["end"]]="",[b.keys.pageUp]="[5~",[b.keys.pageDown]="[6~",[b.keys.delete]="[3~"}local a3=a2[Z]if a3 then W.push(a3)end end elseif Y=="keyReleased"then if Z==b.keys.leftCtrl or Z==b.keys.rightCtrl then H=false elseif Z==b.keys.leftAlt or Z==b.keys.rightAlt then I=false end elseif Y=="keyTyped"then if Z then W.push(Z)end end;X=false else X=true end;if X then sleep(0.05)end end end;L(b.term,"1",W.pop)for q,a4 in ipairs({e.find("monitor")})do a4.setTextScale(.5)a4.write("Initializing...")L(a4,tostring(q+1),function()end)end diff --git a/prod/Hyperion-firmware-cct/boot/cct/boot.lua b/prod/Hyperion-firmware-cct/boot/cct/boot.lua new file mode 100644 index 0000000..d2d7a6e --- /dev/null +++ b/prod/Hyperion-firmware-cct/boot/cct/boot.lua @@ -0,0 +1 @@ +local a=({...})[1]or"/$"local term=term;local os=os;local function b(c)local d,e=term.getCursorPos()local f,g=term.getSize()for h=1,#c do local i=c:sub(h,h)if i=="\n"then e=e+1;d=1 elseif i=="\t"then local j=4;local k=j-(d-1)%j;term.write(string.rep(" ",k))d=d+k elseif i=="\b"then if d>1 then d=d-1;term.setCursorPos(d,e)term.write(" ")term.setCursorPos(d,e)end else if d<=f and e<=g then term.setCursorPos(d,e)term.write(i)d=d+1 end end;if d>f then d=1;e=e+1 end;if e-1>=g then term.scroll(1)e=g;term.setCursorPos(d,e)end end;term.setCursorPos(d,e)end;local function l(m)term.setBackgroundColor(0x1)term.setTextColor(0x4)term.clear()term.setCursorPos(1,1)term.write("A critical error occurred while loading the system:")term.setCursorPos(1,3)b(m)while true do end end;term.setCursorBlink(false)local n,m=xpcall(function()local o={BOOT_DRIVE_PATH=a}local p={coroutine=true,debug=true,_VERSION=true,assert=true,collectgarbage=true,error=true,gcinfo=true,getmetatable=true,ipairs=true,__inext=true,load=true,math=true,next=true,pairs=true,pcall=true,rawequal=true,rawget=true,rawlen=true,rawset=true,select=true,setmetatable=true,string=true,table=true,tonumber=true,tostring=true,type=true,xpcall=true,_G=true}local debug=debug;for h,q in pairs(_G)do if not p[h]or p[h]==nil then o[h]=q;_G[h]=nil end end;local r={[o.keys.enter]="\n",[o.keys.tab]="\t",[o.keys.backspace]="\b",[o.keys.up]="\17",[o.keys.down]="\18",[o.keys.left]="\19",[o.keys.right]="\20"}function sleep(s)local t=o.os.clock()+s;while t>o.os.clock()do end end;o.term.setPaletteColor(0x1,0xFFFFFF)o.term.setPaletteColor(0x2,0xFF0000)o.term.setPaletteColor(0x4,0x00FF00)o.term.setPaletteColor(0x8,0x0000FF)o.term.setPaletteColor(0x10,0x00FFFF)o.term.setPaletteColor(0x20,0xFF00FF)o.term.setPaletteColor(0x40,0xFFFF00)o.term.setPaletteColor(0x80,0xFF6D00)o.term.setPaletteColor(0x100,0x6DFF55)o.term.setPaletteColor(0x200,0x24FFFF)o.term.setPaletteColor(0x400,0x924900)o.term.setPaletteColor(0x800,0x6D6D55)o.term.setPaletteColor(0x1000,0xDBDBAA)o.term.setPaletteColor(0x2000,0x6D00FF)o.term.setPaletteColor(0x4000,0xB6FF00)o.term.setPaletteColor(0x8000,0x000000)local function u(v)local w=o.fs.open(v,"r")if not w then l("Could not open file: "..v)end;local x=w.readAll()w.close()return x end;local y=load(u(a.."/boot/kernel.lua"),"@Kernel")local z=load(u(a.."/boot/cct/initdisks"),"@Init_disks")(o)local A=load(u(a.."/boot/initfs"),"@InitFs")()if not y then l("Could not load kernel.")end;if not z then l("Could not load initdisks.")end;if not A then l("Could not load initfs.")end;if not o.fs.exists("/nvram.dat")then local w=o.fs.open("/nvram.dat","w")w.write("Hello, World!")w.close()end;local B;if o.fs.exists("/startup.lua")then B="/startup.lua"elseif o.fs.exists("/eeprom")then B="/eeprom"end;local C={}local function D(E,...)table.insert(C,{E,...})end;local F={[0x000000]=0x0001,[0xFFFFFF]=0x0002,[0xFF0000]=0x0004,[0x00FF00]=0x0008,[0x0000FF]=0x0010,[0x00FFFF]=0x0020,[0xFF00FF]=0x0040,[0xFFFF00]=0x0080,[0xFF6D00]=0x0100,[0x6DFF55]=0x0200,[0x24FFFF]=0x0400,[0x924900]=0x0800,[0x6D6D55]=0x1000,[0xDBDBAA]=0x2000,[0x6D00FF]=0x4000,[0xB6FF00]=0x8000}local G,H=0x6D6D55,0x000000;local I,J,K,L={},{},{},0;local function M(N,O)local P=nil;local Q=math.huge;for R,S in pairs(N)do if R==O then return R end;local T=math.abs(R-O)if T=16 then K[V]=J[V]J[V]=nil;I[V]=nil;return K[V]end;return J[V]end;local W=M(F,V)if not W then return nil end;local X=F[W]J[V]=X;I[V]=1;return X end;local Y={o.peripheral.find("monitor")}for h=1,#Y do Y[h].setTextScale(.5)Y[h].clear()Y[h].setCursorPos(1,1)Y[h].write("Initializing...")end;local Z={getEpochMs=function()return o.os.epoch("utc")end,getUptime=function()return o.os.clock()*1000 end,date=function()return o.os.date("!%Y-%m-%dT%H:%M:%SZ",o.os.epoch("utc")/1000)end,getMachineEvent=function()if#C>0 then return table.unpack(table.remove(C,1))else return nil end end,getEEPROM=function()return u(B)end,setEEPROM=function(S,c)local g=o.fs.open(B,"w")g.write(c)g.close()end,initfs=A,disks=z,screenCtl={print=function(S,c)b(c.."\n")end,printInline=function(S,c)b(c)end,clear=function()o.term.clear()o.term.setCursorPos(1,1)end,setCursorPos=function(S,d,e)o.term.setCursorPos(d,e)end,getCursorPos=function()return o.term.getCursorPos()end,getSize=function()return o.term.getSize()end,setBackgroundColor=function(S,_)o.term.setBackgroundColor(U(_))end,setTextColor=function(S,_)o.term.setTextColor(U(_))end,getBackgroundColor=function()return H end,getTextColor=function()return G end,enable=function()end,disable=function()end},architecture="cct",getNvram=function()return u("/nvram.dat")end,setNvram=function(S,c)local g=o.fs.open("/nvram.dat","w")g.write(c)g.close()end,firmware=o,reboot=false,beep=function()end}o.term.setBackgroundColor(0x8000)o.term.setTextColor(0x1000)o.term.clear()o.term.setCursorPos(1,1)local a0=coroutine.create(function()local n,m=xpcall(y,debug.traceback,Z)if not n and not Z.reboot then l(m)end;if m then o.os.reboot()else o.os.shutdown()end end)function coroutine.resumeWithTimeout(a1,a2,...)local a3=Z.getEpochMs()debug.sethook(a1,function()if Z.getEpochMs()>a3+a2 then return coroutine.yield("timeout")end end,"",1000)local a4={coroutine.resume(a1,...)}if a4[1]and a4[2]=="timeout"then return"timeout"elseif a4[1]==false then return"error",a4[2]else debug.sethook(a1)return"success",table.unpack(a4,2)end end;Z.screenCtl:print("Loaded in "..tostring(o.os.clock()).." seconds.\n")while true do local a5,m=coroutine.resumeWithTimeout(a0,50)o.os.queueEvent("NoSleep")local a6=false;while not a6 do local E={coroutine.yield()}if E[1]=="key"then D("keyPressed",1,E[2])if r[E[2]]then D("keyTyped",1,r[E[2]])end elseif E[1]=="char"then D("keyTyped",1,E[2])elseif E[1]=="key_up"then D("keyReleased",1,E[2])elseif E[1]=="disk"then D("componentAdded","disk")elseif E[1]=="disk_eject"then D("componentRemoved","disk")elseif E[1]=="modem_message"then D("modem_message",table.unpack(E,2))elseif E[1]=="rednet_message"then D("rednet_message",table.unpack(E,2))elseif E[1]=="http_success"then D("http_success",table.unpack(E,2))elseif E[1]=="http_failure"then D("http_failure",table.unpack(E,2))elseif E[1]=="NoSleep"then a6=true end end;if a5=="error"or coroutine.status(a0)=="dead"then if Z.reboot then o.os.reboot()end;l("Kernel error: "..tostring(m))coroutine.yield("key")end;z:refresh()end end,debug.traceback)if not n then l("Fatal error during boot: "..m)end;while true do coroutine.yield("key")end diff --git a/prod/Hyperion-firmware-cct/boot/cct/eeprom b/prod/Hyperion-firmware-cct/boot/cct/eeprom new file mode 100644 index 0000000..9bba429 --- /dev/null +++ b/prod/Hyperion-firmware-cct/boot/cct/eeprom @@ -0,0 +1 @@ +local a=({...})[1]or"/$"local b={...}local c={keys=true,bit32=true,bit=true,ccemux=true,config=true,coroutine=true,debug=true,fs=true,http=true,mounter=true,os=true,periphemu=true,peripheral=true,redstone=true,rs=true,term=true,utf8=true,_HOST=true,_CC_DEFAULT_SETTINGS=true,_CC_DISABLE_LUA51_FEATURES=true,_VERSION=true,assert=true,collectgarbage=true,error=true,gcinfo=true,getfenv=true,getmetatable=true,ipairs=true,__inext=true,load=true,loadstring=true,math=true,newproxy=true,next=true,pairs=true,pcall=true,rawequal=true,rawget=true,rawlen=true,rawset=true,select=true,setfenv=true,setmetatable=true,string=true,table=true,tonumber=true,tostring=true,type=true,unpack=true,xpcall=true,turtle=true,pocket=true,commands=true,_G=true}local d={}for e in pairs(_G)do if not c[e]then table.insert(d,e)end end;for f,e in ipairs(d)do _G[e]=nil end;local g=_G.term.native()for f,h in ipairs{"nativePaletteColor","nativePaletteColour","screenshot"}do g[h]=_G.term[h]end;_G.term=g;if _G.http then _G.http.checkURL=_G.http.checkURLAsync;_G.http.websocket=_G.http.websocketAsync end;if _G.commands then _G.commands=_G.commands.native end;if _G.turtle then _G.turtle.native,_G.turtle.craft=nil end;local i={os={"version","pullEventRaw","pullEvent","run","loadAPI","unloadAPI","sleep"},http=_G.http and{"get","post","put","delete","patch","options","head","trace","listen","checkURLAsync","websocketAsync"},fs={"complete","isDriveRoot"}}for e,j in pairs(i)do for f,k in ipairs(j)do _G[e][k]=nil end end;local l=error;_G.error=function()end;_G.term.redirect=function()end;function _G.term.native()_G.term.native=nil;_G.term.redirect=nil;_G.error=l;term.setBackgroundColor(32768)term.setTextColor(1)term.setCursorPos(1,1)term.setCursorBlink(true)term.clear()local m=fs.open(a.."/boot/cct/boot.lua","r")if m==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;local n,o=loadstring(m.readAll(),"@bootloader")m.close()if n==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write(o)term.setCursorPos(1,3)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;setfenv(n,_G)local p=os.shutdown;os.shutdown=function()os.shutdown=p;return n(a)end end;if debug then local function q(r,s,t,u)local v,w,x=1,debug.getupvalue(r[s],u)while w~=t and w~=nil do w,x=debug.getupvalue(r[s],v)v=v+1 end;r[s]=x or r[s]end;q(_G,"loadstring","nativeloadstring",1)q(_G,"load","nativeload",5)if http then q(http,"request","nativeHTTPRequest",3)end;q(os,"shutdown","nativeShutdown",1)q(os,"reboot","nativeReboot",1)if turtle then q(turtle,"equipLeft","v",1)q(turtle,"equipRight","v",1)end;do local v,w,x=1,debug.getupvalue(peripheral.isPresent,2)while w~="native"and w~=nil do w,x=debug.getupvalue(peripheral.isPresent,v)v=v+1 end;_G.peripheral=x or peripheral end end diff --git a/prod/Hyperion-firmware-cct/boot/cct/initdisks b/prod/Hyperion-firmware-cct/boot/cct/initdisks new file mode 100644 index 0000000..dc41dfd --- /dev/null +++ b/prod/Hyperion-firmware-cct/boot/cct/initdisks @@ -0,0 +1 @@ +local a=({...})[1]local b=a.BOOT_DRIVE_PATH;local c=a.fs;local d=a.peripheral;local e={}local f={"top","bottom","left","right","front","back"}function e.getNames()local g={}for h=1,#f do local i=f[h]if d.isPresent(i)then table.insert(g,i)if d.hasType(i,"peripheral_hub")then local j=d.call(i,"getNamesRemote")for k,l in ipairs(j)do table.insert(g,l)end end end end;return g end;function e.isPresent(l)if d.isPresent(l)then return true end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return true end end;return false end;function e.getType(e)if type(e)=="string"then if d.isPresent(e)then return d.getType(e)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"getTypeRemote",e)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(m.types)end end;function e.hasType(e,n)if type(e)=="string"then if d.isPresent(e)then return d.hasType(e,n)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"hasTypeRemote",e,n)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return m.types[n]~=nil end end;function e.getMethods(l)if d.isPresent(l)then return d.getMethods(l)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"getMethodsRemote",l)end end;return nil end;function e.getName(e)local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return m.name end;function e.call(l,o,...)if d.isPresent(l)then return d.call(l,o,...)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"callRemote",l,o,...)end end;return nil end;function e.wrap(l)local p=e.getMethods(l)if not p then return nil end;local q={e.getType(l)}for r=1,#q do q[q[r]]=true end;local s=setmetatable({},{__name="peripheral",name=l,type=q[1],types=q})for k,o in ipairs(p)do s[o]=function(...)return e.call(l,o,...)end end;return s end;function e.find(t,u)local g={}for k,l in ipairs(e.getNames())do if e.hasType(l,t)then local v=e.wrap(l)if u==nil or u(l,v)then table.insert(g,v)end end end;return table.unpack(g)end;local w={}local x={}local function y(z)if not z or z==""then return"/"end;return c.combine("/",z)end;local function A(B,C,D,E)C=y(C)local F={address=B,isReadOnly=function()return D end}function F:spaceUsed()return c.getCapacity(C)-c.getFreeSpace(C)end;function F:spaceTotal()return c.getCapacity(C)end;function F:list(z)local G=c.combine(C,z)if not c.exists(G)or not c.isDir(G)then return nil,"not directory"end;return c.list(G)end;function F:fileExists(z)local G=c.combine(C,z)return c.exists(G)and not c.isDir(G)end;function F:directoryExists(z)local G=c.combine(C,z)return c.exists(G)and c.isDir(G)end;function F:type(z)local G=c.combine(C,z)if not c.exists(G)then return nil elseif c.isDir(G)then return"directory"else return"file"end end;function F:makeDirectory(z)local G=c.combine(C,z)c.makeDir(G)return true end;function F:remove(z)local G=c.combine(C,z)if c.exists(G)then c.delete(G)end;return true end;function F:setLabel(H)E.setLabel(H)end;function F:getLabel(H)return E.getLabel()end;function F:attributes(z)local G=c.combine(C,z)return c.attributes(G)end;function F:open(z,I)local G=c.combine(C,z)return c.open(G,I)end;return F end;x["$"]=A("$",b,false,{setLabel=function(H)local J=c.open("/.label","w")J.write(H)J.close()end,getLabel=function()local J=c.open("/.label","r")if not J then return"$"end;local H=J.readAll()J.close()return H end})x["rom"]=A("rom","/rom",true,{setLabel=function(H)error("Device is read-only")end,getLabel=function()return"cctrom"end})local function K()w={}for k,F in ipairs({e.find("drive")})do if F.isDiskPresent()then w[tostring(F.getDiskID())]=A("cctdisk"..tostring(F.getDiskID()),F.getMountPath(),false,c)end end end;local function L()K()local M={}for B,N in pairs(x)do M[B]=N end;for B,N in pairs(w)do M[B]=N end;return pairs(M)end;return{refresh=K,list=L} diff --git a/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod new file mode 100644 index 0000000..e85aa09 --- /dev/null +++ b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod @@ -0,0 +1 @@ +local a=...a.cct={}a.cct.peripheral={}local b=a.cct.peripheral;local c=a.apis;local d=c.peripheral;local e={"top","bottom","left","right","front","back"}function b.getNames()local f={}for g=1,#e do local h=e[g]if d.isPresent(h)then table.insert(f,h)if d.hasType(h,"peripheral_hub")then local i=d.call(h,"getNamesRemote")for j,k in ipairs(i)do table.insert(f,k)end end end end;return f end;function b.isPresent(k)if d.isPresent(k)then return true end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",k)then return true end end;return false end;function b.getType(b)if type(b)=="string"then if d.isPresent(b)then return d.getType(b)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",b)then return d.call(h,"getTypeRemote",b)end end;return nil else local l=getmetatable(b)if not l or l.__name~="peripheral"or type(l.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(l.types)end end;function b.hasType(b,m)if type(b)=="string"then if d.isPresent(b)then return d.hasType(b,m)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",b)then return d.call(h,"hasTypeRemote",b,m)end end;return nil else local l=getmetatable(b)if not l or l.__name~="peripheral"or type(l.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return l.types[m]~=nil end end;function b.getMethods(k)if d.isPresent(k)then return d.getMethods(k)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",k)then return d.call(h,"getMethodsRemote",k)end end;return nil end;function b.getName(b)local l=getmetatable(b)if not l or l.__name~="peripheral"or type(l.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return l.name end;function b.call(k,n,...)if d.isPresent(k)then return d.call(k,n,...)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",k)then return d.call(h,"callRemote",k,n,...)end end;return nil end;function b.wrap(k)local o=b.getMethods(k)if not o then return nil end;local p={b.getType(k)}for q=1,#p do p[p[q]]=true end;local r=setmetatable({},{__name="peripheral",name=k,type=p[1],types=p})for j,n in ipairs(o)do r[n]=function(...)return b.call(k,n,...)end end;return r end;function b.find(s,t)local f={}for j,k in ipairs(b.getNames())do if b.hasType(k,s)then local u=b.wrap(k)if t==nil or t(k,u)then table.insert(f,u)end end end;return table.unpack(f)end diff --git a/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/22_http.kmod b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/22_http.kmod new file mode 100644 index 0000000..e69de29 diff --git a/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod new file mode 100644 index 0000000..e2af0fd --- /dev/null +++ b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/25_tty.kmod @@ -0,0 +1 @@ +local a=...local b=a.cct.peripheral;local c={[0xFFFFFF]=0x0001,[0xFF0000]=0x0002,[0x00FF00]=0x0004,[0x0000FF]=0x0008,[0x00FFFF]=0x0010,[0xFF00FF]=0x0020,[0xFFFF00]=0x0040,[0xFF6D00]=0x0080,[0x6DFF55]=0x0100,[0x24FFFF]=0x0200,[0x924900]=0x0400,[0x6D6D55]=0x0800,[0xDBDBAA]=0x1000,[0x6D00FF]=0x2000,[0xB6FF00]=0x4000,[0x000000]=0x8000}local d={0xFFFFFF,0xFF0000,0x00FF00,0x0000FF,0x00FFFF,0xFF00FF,0xFFFF00,0xFF6D00,0x6DFF55,0x24FFFF,0x924900,0x6D6D55,0xDBDBAA,0x6D00FF,0xB6FF00,0x000000}local e,f=0x6D6D55,0x000000;local g,h,i,j={},{},{},0;local function k(l,m)local n=nil;local o=math.huge;for p,q in pairs(l)do if p==m then return p end;local r=math.abs(p-m)if r=16 then i[t]=h[t]h[t]=nil;g[t]=nil;return i[t]end;return h[t]end;local u=k(c,t)if not u then return nil end;local v=c[u]h[t]=v;g[t]=1;return v end;local function w(x,y)local z,A=y.getCursorPos()local B,C=y.getSize()for D=1,#x do local E=x:sub(D,D)if E=="\n"then A=A+1;z=1 elseif E=="\t"then local F=4;local G=F-(z-1)%F;y.write(string.rep(" ",G))z=z+G elseif E=="\b"then if z>1 then z=z-1;y.setCursorPos(z,A)y.write(" ")y.setCursorPos(z,A)end else if z<=B and A<=C then y.setCursorPos(z,A)y.write(E)z=z+1 end end;if z>B then z=1;A=A+1 end;if A-1>=C then y.scroll(1)A=C;y.setCursorPos(z,A)end end;y.setCursorPos(z,A)end;a.devfs.data.tty={}a.cct.ctrl,a.cct.alt=false,false;local function H(I)if I then return"T"else return"F"end end;local function J(K,L,M)K.setPaletteColor(0x1,0xFFFFFF)K.setPaletteColor(0x2,0xFF0000)K.setPaletteColor(0x4,0x00FF00)K.setPaletteColor(0x8,0x0000FF)K.setPaletteColor(0x10,0x00FFFF)K.setPaletteColor(0x20,0xFF00FF)K.setPaletteColor(0x40,0xFFFF00)K.setPaletteColor(0x80,0xFF6D00)K.setPaletteColor(0x100,0x6DFF55)K.setPaletteColor(0x200,0x24FFFF)K.setPaletteColor(0x400,0x924900)K.setPaletteColor(0x800,0x6D6D55)K.setPaletteColor(0x1000,0xDBDBAA)K.setPaletteColor(0x2000,0x6D00FF)K.setPaletteColor(0x4000,0xB6FF00)K.setPaletteColor(0x8000,0x000000)a.devfs.data["tty"][L]=function(N,O)if N=="type"then return"Terminal"elseif N=="open"then local C={read=function(P)local Q=""for D=1,P or 1 do local R={M()}if R[1]then Q=Q..R[1]end end;if Q==""then Q=nil end;return Q end,write=function(S)w(S,K)end,size=function()local T={K.getSize()}return table.concat(T,";")end,clear=function()K.clear()K.setCursorPos(1,1)end,gpos=function()local T={K.getCursorPos()}return table.concat(T,";")end,spos=function(z,A)return K.setCursorPos(z,A)end,sfgc=function(E)e=E;return K.setTextColor(s(E))end,sbgc=function(E)f=E;return K.setBackgroundColor(s(E))end,gfgc=function()return e end,gbgc=function()return f end,gctrl=function()return H(a.cct.ctrl)..";"..H(a.cct.alt)end,gplt=function()return d end}if O=="rw"then return C elseif O=="r"then C["write"]=nil;return C elseif O=="w"then C["read"]=nil;return C end end end end;local U=a.newFifo()a.cct.fifo=U;J(a.apis.term,"1",U.pop)for D,V in ipairs({b.find("monitor")})do V.setTextScale(.5)V.write("Initializing...")J(V,tostring(D+1),function()end)end diff --git a/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/30_deamon.kmod b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/30_deamon.kmod new file mode 100644 index 0000000..4d25109 --- /dev/null +++ b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/30_deamon.kmod @@ -0,0 +1 @@ +local a=...local b=a.apis.keys;a.processes.cctdeamon=function()local c=false;while true do local d={a.EFI:getMachineEvent()}if d[1]then local e=d[1]local f=d[3]local g={[b.a]=1,[b.b]=2,[b.c]=3,[b.d]=4,[b.e]=5,[b.f]=6,[b.g]=7,[b.h]=8,[b.i]=9,[b.j]=10,[b.k]=11,[b.l]=12,[b.m]=13,[b.n]=14,[b.o]=15,[b.p]=16,[b.q]=17,[b.r]=18,[b.s]=19,[b.t]=20,[b.u]=21,[b.v]=22,[b.w]=23,[b.x]=24,[b.y]=25,[b.z]=26}if e=="keyPressed"then if f==b.leftCtrl or f==b.rightCtrl then a.cct.ctrl=true elseif f==b.leftAlt or f==b.rightAlt then a.cct.alt=true end;if a.cct.ctrl then local h=g[f]if h then if h==3 then for i,j in ipairs(syscall.getTasks())do syscall.sigsend(j,1)end else a.cct.fifo.push(string.char(h))end end else local k={[b.up]="",[b.down]="",[b.right]="",[b.left]="",[b.home]="",[b["end"]]="",[b.pageUp]="[5~",[b.pageDown]="[6~",[b.delete]="[3~"}local l=k[f]if l then a.cct.fifo.push(l)end end elseif e=="keyReleased"then if f==b.leftCtrl or f==b.rightCtrl then a.cct.ctrl=false elseif f==b.leftAlt or f==b.rightAlt then a.cct.alt=false end elseif e=="keyTyped"then if f then a.cct.fifo.push(f)end elseif e=="http_success"then a.cct.httpqueue[d[2]]=nil;a.cct.httpresponse[d[2]]=d[3]elseif e=="http_failure"then a.cct.httpqueue[d[2]]=nil;a.cct.httperror[d[2]]=d[3]end;c=false else c=true end;if c then sleep(0.05)end end end diff --git a/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/51_gpio.kmod b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/51_gpio.kmod new file mode 100644 index 0000000..0c5efa9 --- /dev/null +++ b/prod/Hyperion-firmware-cct/lib/modules/cc-tweaked/51_gpio.kmod @@ -0,0 +1 @@ +local a=...local b=a.apis.rs;local c={top=1,bottom=2,left=3,right=4,front=5,back=6}local function d(e)return function(f,g)if f=="w"then if type(g)~="boolean"then error("data: expected bool")end;b.setOutput(e,g)elseif f=="wa"then if type(g)~="number"then error("data: expected bool")end;b.setAnalogOutput(e,g)elseif f=="r"then return b.getInput(e)elseif f=="ra"then return b.getAnalogInput(e)end end end;for e,h in pairs(c)do local i=d(e)a.gpio[e]=i;a.gpio[h]=i end diff --git a/prod/Hyperion-firmware-oc/boot/oc/boot.lua b/prod/Hyperion-firmware-oc/boot/oc/boot.lua new file mode 100644 index 0000000..ff2d61d --- /dev/null +++ b/prod/Hyperion-firmware-oc/boot/oc/boot.lua @@ -0,0 +1,41 @@ +local lua = { + coroutine = true, + debug = true, + _HOST = true, + _VERSION = true, + assert = true, + collectgarbage = true, + error = true, + gcinfo = true, + getfenv = true, + getmetatable = true, + ipairs = true, + __inext = true, + load = true, + math = true, + next = true, + pairs = true, + pcall = true, + rawequal = true, + rawget = true, + rawlen = true, + rawset = true, + select = true, + setfenv = true, + setmetatable = true, + string = true, + table = true, + tonumber = true, + tostring = true, + type = true, + xpcall = true, + _G=true +} + +local apis={} +for i,v in pairs(_G) do + if not lua[i] or lua[i]==nil then + apis[i]=v + _G[i]=nil + end +end \ No newline at end of file diff --git a/prod/Hyperion-firmware-oc/boot/oc/eeprom b/prod/Hyperion-firmware-oc/boot/oc/eeprom new file mode 100644 index 0000000..8daa779 --- /dev/null +++ b/prod/Hyperion-firmware-oc/boot/oc/eeprom @@ -0,0 +1,18 @@ +checkArg=nil +local oldcomputer=computer +_G.computer=nil +local os=os +_G.os=nil + +function component.wrap(address) + local methods=oldcomponent.methods(address) + local object={} + for _,method in ipairs(methods) do + object[method]=function(_,...) + return oldcomponent.invoke(address,method,...) + end + end + return object +end + +local \ No newline at end of file diff --git a/prod/Hyperion-firmware-oc/boot/oc/initfs.lua b/prod/Hyperion-firmware-oc/boot/oc/initfs.lua new file mode 100644 index 0000000..a7948ae --- /dev/null +++ b/prod/Hyperion-firmware-oc/boot/oc/initfs.lua @@ -0,0 +1 @@ +local fs={} \ No newline at end of file diff --git a/prod/Hyperion-kernel/boot/fstab b/prod/Hyperion-kernel/boot/fstab new file mode 100644 index 0000000..0f7573d --- /dev/null +++ b/prod/Hyperion-kernel/boot/fstab @@ -0,0 +1,4 @@ +U $;/ +U devfs0000;/dev/ +U tmpfs0000;/tmp/ +U procfs0000;/proc/ \ No newline at end of file diff --git a/prod/Hyperion-kernel/boot/initfs b/prod/Hyperion-kernel/boot/initfs new file mode 100644 index 0000000..d3a154b --- /dev/null +++ b/prod/Hyperion-kernel/boot/initfs @@ -0,0 +1,84 @@ +-- :Minify:-- +local fs = {} +local disks = {} +local mounts = {} + +local function resolve(path) + local mountPoint = "/" + for mount, disk in pairs(mounts) do + if path:sub(1, #mount) == mount then + if not mountPoint or #mount > #mountPoint then + mountPoint = mount + end + end + end + local newPath = path:sub(#mountPoint + 1) + return disks[mounts[mountPoint]], newPath +end + +function fs.update(initdisks) + disks = {} + for k, v in initdisks.list() do disks[k] = v end +end + +function fs.exists(path) + local disk, newPath = resolve(path) + return disk:directoryExists(newPath) or disk:fileExists(newPath) +end + +function fs.isFile(path) + local disk, newPath = resolve(path) + return disk:fileExists(newPath) +end + +function fs.isDir(path) + local disk, newPath = resolve(path) + return disk:directoryExists(newPath) +end + +function fs.list(path) + local disk, newPath = resolve(path) + return disk:list(newPath) +end + +function fs.makeDir(path) + local disk, newPath = resolve(path) + return disk:makeDirectory(newPath) +end + +function fs.remove(path) + local disk, newPath = resolve(path) + return disk:remove(newPath) +end + +function fs.readAllText(path) + local disk, newPath = resolve(path) + local handle = disk:open(newPath, "r") + if not handle then return nil end + local content = handle.readAll() + handle.close() + return content +end + +function fs.writeAllText(path, text) + local disk, newPath = resolve(path) + local handle = disk:open(newPath, "w") + handle.write(text) + handle.close() +end + +function fs.appendAllText(path, text) + local disk, newPath = resolve(path) + local handle = disk:open(newPath, "a") + handle.write(text) + handle.close() +end + +function fs.load(path) return load(fs.readAllText(path), path) end + +function fs.mount(disk, mountPoint) + if not disks[disk] then return end + mounts[mountPoint] = disk +end + +return fs diff --git a/prod/Hyperion-kernel/boot/kernel.lua b/prod/Hyperion-kernel/boot/kernel.lua new file mode 100644 index 0000000..edba9cd --- /dev/null +++ b/prod/Hyperion-kernel/boot/kernel.lua @@ -0,0 +1 @@ +local a=...a.beep(440,500)local b=a.screenCtl;local c=a.initfs;local d=a.disks;local e=a.architecture;local f={}f.LOG_Text=""f.version="HyperionOS V1.2.4"f.process="Kernel"f.users={[0]="root",[1]="User"}f.hostname="hyperion"f.groups={}f.uid=0;f.gid=0;f.status="start"f.key={}f.cache={}f.cache.preload={}f._G=_G;f.sleep=sleep;_G.sleep=nil;local g=false;function f.log(h,i,j)j=j or 0x6D6D6D;f.LOG_Text=f.LOG_Text..tostring(a:date()).." "..f.users[f.uid].." "..f.process.."["..tostring(i or"INFO").."]: "..h.."\n"if f.status=="start"then b:setTextColor(j)b:print(tostring(a:date()).." "..f.users[f.uid].." "..f.process.."["..tostring(i or"INFO").."]: "..h)elseif f.status=="term"then f.standbyTask=f.currentTask;f.currentTask=f.kernelTask;local k=f.vfs.open("/dev/console","w")f.vfs.devctl(k,"sfgc",j)f.vfs.write(k,tostring(a:date()).." "..f.users[f.uid].." "..f.process.."["..tostring(i or"INFO").."]: "..h.."\n")f.vfs.close(k)f.currentTask=f.standbyTask end end;function f.PANIC(h)if f.status~="Panic"then f.log("PANIC: "..h,"PANIC",0xFF0000)pcall(f["saveLog"])f.status="Panic"f.reason=h;b:enable()b:setTextColor(0xFF0000)b:setBackgroundColor(0x000000)b:clear()b:setCursorPos(1,1)b:print(f.LOG_Text)b:print("KERNEL PANIC!\n"..h.."\nSystem halted.")b:print("Press any key to continue...")f.exitMain=true end;while true do local l={a:getMachineEvent()}if l[1]=="keyPressed"then break end end;a.reboot=true;error("KERNEL PANIC")end;f.panic=f.PANIC;if g then b:setTextColor(0xFFFFFF)b:setBackgroundColor(0x0000FF)b:clear()local m,n=b:getSize()b:setCursorPos(3,5)b:print(":(")b:setCursorPos(3,7)b:print("Your PC ran into a problem and needs to restart. We're just collecting some error")b:setCursorPos(3,8)b:print("info, and then we'll restart for you.\n")b:setCursorPos(3,n-5)b:print("Stop code: average windows experience")b:setCursorPos(1,n)b:print("Press any key to continue... jk reboot it yourself lazy")while true do end end;f.log("Kernel loaded.")f.log("Mounting init disks...")d.refresh()c.update(d)f.disks={}for o,p in d.list()do f.disks[p.address]=p end;c.mount("$","/")local q=c.readAllText("/boot/fstab")local r=function(s,t,u)assert(#t==1,"only delim len 1 supported for now")u=(u or 0)-1;local v={}local w=""for x=1,#s do local j=string.sub(s,x,x)if#v~=u and j==t then table.insert(v,w)w=""else w=w..j end end;table.insert(v,w)return v end;if not c.isFile("/boot/boot.cfg")then f.log("First boot detected writing boot.cfg","INFO",0x00FF00)c.writeAllText("/boot/boot.cfg",c.readAllText("/boot/safeboot.cfg"))f.firstBoot=true end;local y,z=load(c.readAllText("/boot/boot.cfg"),"@boot.cfg")if not y then f.PANIC("Failed to load /boot/boot.cfg: "..tostring(z))end;local A,B=pcall(y)if not A then f.PANIC("Error in /boot/boot.cfg: "..tostring(B))end;f.config=B;local C=false;for x,p in ipairs(r(q,"\n"))do if p:sub(1,1)=="U"then local D=""for x=3,#p do if p:sub(x,x)==";"then if x==3 then f.log("Invalid fstab line... Skipping.","WARN",0xFF8800)C=true;break end;D=p:sub(3,x-1)end end;if not C then local E=p:sub(#D+4)c.mount(D,E)else C=false end end end;f.log("Disks initialized")function f.saveLog()if f.status=="running"then local k=f.vfs.open("/var/log/syslog.log","w")f.vfs.write(k,f.LOG_Text)f.vfs.close(k)else c.writeAllText("/var/log/syslog.log",f.LOG_Text)end end;function f.newFifo()local F={}F.push=function(G)table.insert(F,G)end;F.pop=function()return table.remove(F,1)end;return F end;function f.newUUID()local H="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"local I=""for x=1,#H do local j=H:sub(x,x)if j=="x"then I=I..string.format("%x",math.random(0,15))elseif j=="y"then I=I..string.format("%x",math.random(8,11))else I=I..j end end;return I end;f.syscalls={}local J={[0]={}}for x=0,100 do J[x]={}end;f.log("Gathering modules")for o,x in ipairs(c.list("/lib/modules"))do local K=c.list("/lib/modules/"..x)if not K then f.log("WARNING: could not list /lib/modules/"..x.." (skipping)","WARN",0xFF8800)else for o,p in ipairs(K)do local L=tonumber(p:sub(1,2))if L then J[L+1][#J[L+1]+1]="/lib/modules/"..x.."/"..p end end end end;f.ifs=c;f.apis=a.firmware;f.EFI=a;f.arch=e;f.initdisks=d;f.screen=b;f.processes={}f.fstab=q;f.kernelTask={name="kernel",status="R",pid=0,tgid=0,uid=0,fd={},exit="",sleep=0,ivs=0,vs=0,children={},syscallReturn={},cwd="/",timeSlice=0,lastTime=0,totalTime=0,numRuns=0}f.currentTask=f.kernelTask;function f.shutdown()f.exitMain=true;f.status="shutdown"end;function f.reboot()f.exitMain=true;f.status="reboot"end;f.syscalls["time"]=function()return f.EFI:getEpochMs()end;f.syscalls["date"]=function()return f.EFI:date()end;f.syscalls["log"]=f.log;f.syscalls["getUptime"]=function()return f.EFI:getUptime()end;f.syscalls["getUsername"]=function(M)return f.users[M or f.uid]end;f.syscalls["getHostname"]=function()return f.hostname end;f.syscalls["getHost"]=function()return f.apis._HOST end;f.syscalls["version"]=function()return f.version end;f.syscalls["setHostname"]=function(N)if f.uid~=0 then error("Permission denied")end;f.hostname=N end;f.syscalls["arch"]=function()return e end;f.syscalls["sysdump"]=function()local v={}for x,p in pairs(f.syscalls)do v[#v+1]=x end;return v end;f.syscalls["reboot"]=f.reboot;f.syscalls["shutdown"]=f.shutdown;f.log("Running modules")for o,O in ipairs(J)do for o,p in ipairs(O)do if f.config.showModLoad then f.log("Loading module "..p,"DBUG",0x00FFFF)end;local P=c.readAllText(p)if not P then f.panic("Failed to read module "..p)end;local Q,z=load(P,"@"..p)if not Q then f.panic("ModuLoadErr: "..tostring(z))end;local R,z=xpcall(Q,debug.traceback,f)if not R then f.panic("ModuRunErr: "..tostring(z))end;if f.config.showModLoad then f.log("Loaded module "..p,"DBUG",0x00FFFF)end end end;f.log("Kernel initialized successfully.")f.saveLog()f.status="running"b:disable()f.main()if f.status=="panic"then f.panic(f.reason)end;if f.status=="reboot"then a.reboot=true;return true end diff --git a/prod/Hyperion-kernel/boot/safeboot.cfg b/prod/Hyperion-kernel/boot/safeboot.cfg new file mode 100644 index 0000000..1c58e65 --- /dev/null +++ b/prod/Hyperion-kernel/boot/safeboot.cfg @@ -0,0 +1,12 @@ +-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING! +-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE! + +-- This file is auto-generated during the build process. +-- DEFAULT BOOT CONFIGURATION FILE +return { + initPath = "/sbin/init", + maxOpenFiles = 128, + maxFilesPerTask = 16, + preempt=true, + logTaskExit=true +} \ No newline at end of file diff --git a/prod/Hyperion-kernel/etc/passwd b/prod/Hyperion-kernel/etc/passwd new file mode 100644 index 0000000..434ccc5 --- /dev/null +++ b/prod/Hyperion-kernel/etc/passwd @@ -0,0 +1 @@ +0:0:root:/root:/bin/hysh \ No newline at end of file diff --git a/prod/Hyperion-kernel/etc/shadow b/prod/Hyperion-kernel/etc/shadow new file mode 100644 index 0000000..e69de29 diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod new file mode 100644 index 0000000..3d9b187 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod @@ -0,0 +1 @@ +local a=...a.allowGlobalOverwrites=true;function string.hasSuffix(b,c)return string.sub(b,#c+1)==c end;function string.hasPrefix(b,d)return string.sub(b,1,#d)==d end;function string.getSuffix(b,d)return string.sub(b,#d+1)end;function string.getPrefix(b,c)return string.sub(b,1,#c)end;function string.join(b,...)return table.concat(table.pack(b,...))end;function string.delim(b,...)return table.concat(table.pack(...),b)end;function string.split(b,e,f)assert(#e==1,"only delim len 1 supported for now")if not b then return false end;f=(f or 0)-1;local g={}local h=""for i=1,#b do local j=string.sub(b,i,i)if#g~=f and j==e then table.insert(g,h)h=""else h=h..j end end;table.insert(g,h)return g end;function table.deepcopy(k,l)l=l or{}if type(k)~='table'then return k elseif l[k]then return l[k]end;local m={}l[k]=m;for n,o in next,k,nil do local p=table.deepcopy(n,l)local q=table.deepcopy(o,l)m[p]=q end;return m end;function table.hasKey(r,s)for i,o in pairs(r)do if i==s then return o end end;return false end;function table.hasVal(r,s)for i,o in pairs(r)do if o==s then return i end end;return false end;local function t(u,v)v=v or{}if v[u]then return'"[Circular Reference]"'end;v[u]=true;local w="{"local x=true;for i,o in pairs(u)do if not x then w=w..","end;x=false;if type(i)=="string"then w=w.."[\""..i.."\"]="elseif type(i)=="number"then w=w.."["..tostring(i).."]="end;if type(o)=="table"then w=w..t(o,v)elseif type(o)=="string"then w=w.."[=["..o.."]=]"elseif type(o)=="number"or type(o)=="boolean"then w=w..tostring(o)elseif type(o)=="function"then w=w.."\""..tostring(o).."\""elseif type(o)=="thread"then w=w.."\""..tostring(o).."\""else error("serialization of type \""..type(o).."\" is not supported")end end;v[u]=nil;w=w.."}"return w end;local y=type;local z=getmetatable;function type(A,B)if B then return y(A)end;if y(A)~="table"then return y(A)else if y(z(A))=="table"then local C=z(A)if C.__type then return C.__type end else return"table"end end end;function getmetatable(A)if y(A)~="table"then return end;if y(z(A))=="table"then if z(A).__isuserdata then if y(z(A).__usermeta)=="function"then return z(A).__usermeta()else return z(A).__usermeta end else return z(A)end else return z(A)end end;function isEqualToAny(D,...)local E={...}for i=0,#E do if D==E[i]then return true end end;return false end;function isEqualToAll(D,...)local E={...}for i=0,#E do if D~=E[i]then return false end end;return true end;function table.keys(F)local D={}for G in pairs(F)do table.insert(D,G)end;return D end;function table.values(F)local D={}for H,G in pairs(F)do table.insert(D,G)end;return D end;function table.indexOf(F,I)for i,o in ipairs(F)do if o==I then return i end end;return-1 end;function table.merge(...)local E={...}local J={}local K={}for H,F in ipairs(E)do for i,o in pairs(F)do J[i]=o end;for i,o in ipairs(F)do K[#K+1]=o end end;for i,o in ipairs(K)do J[i]=o end;return J end;function string.replace(L,M,N)local O={}local i=1;local G=#L;local P=#M;while i<=G do local Q=true;if i+P-1<=G then for R=1,P do if L:sub(i+R-1,i+R-1)~=M:sub(R,R)then Q=false;break end end else Q=false end;if Q then table.insert(O,N)i=i+P else table.insert(O,L:sub(i,i))i=i+1 end end;return table.concat(O)end;function toHex(S)return string.format("%X",S)end;local function T()local U={}return setmetatable(U,{__index=function(self,V)local W=rawget(self,V)if W~=nil then return W end;return function(...)local X=table.pack(coroutine.yield("syscall",V,...))if X[1]then return table.unpack(X,2,X.n)else error(X[2],2)end end end,__newindex=function(self,n,o)rawset(self,n,o)end,__metatable=false})end;syscall=T()_makeSyscallProxy=T;table.serialize=t diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod new file mode 100644 index 0000000..568a93e --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod @@ -0,0 +1 @@ +local a=...local b={}a.vfs=b;b.mounts={["$"]="/"}b.disks=a.disks;local c=0x02;local function d(e,f)return math.floor(e/2^f)%2==1 end;local function g(h)if not h or h==""then return{}end;local i={}local j=1;local k=0;local l=h:byte(1)if l==0x02 or l==0x01 then k=l;j=2 end;while j<=#h do if j>#h then break end;local m=h:byte(j)j=j+1;if m==0 or j+m-1>#h then break end;local n=h:sub(j,j+m-1)j=j+m;local o,p,q,r,s;if k==0x02 then if j+6>#h then break end;o=h:byte(j)j=j+1;p=h:byte(j)+h:byte(j+1)*256;j=j+2;q=h:byte(j)+h:byte(j+1)*256;j=j+2;r=h:byte(j)+h:byte(j+1)*256;j=j+2 elseif k==0x01 then if j+4>#h then break end;o=h:byte(j)j=j+1;p=h:byte(j)j=j+1;q=h:byte(j)j=j+1;r=h:byte(j)+h:byte(j+1)*256;j=j+2 else if j+2>#h then break end;o=0x00;p=h:byte(j)j=j+1;q=h:byte(j)j=j+1;r=h:byte(j)j=j+1 end;if j>#h then break end;local t=h:byte(j)j=j+1;s=""if t>0 then s=h:sub(j,j+t-1)j=j+t end;i[n]={etype=o,owner=p,group=q,perms=r,cmeta=s}end;return i end;local function u(v)local w=string.char(c)for n,x in pairs(v)do local y=x.perms%256;local z=math.floor(x.perms/256)%256;local A=(x.owner or 0)%256;local B=math.floor((x.owner or 0)/256)%256;local C=(x.group or 0)%256;local D=math.floor((x.group or 0)/256)%256;w=w..string.char(#n)..n..string.char(x.etype or 0x00)..string.char(A,B,C,D,y,z)..string.char(#x.cmeta)..x.cmeta end;return w end;local E="^[A-Za-z0-9_.+%-%@%(%)%[%]]+$"local function F(G)local H=G:sub(1,1)=="/"local I={}for J in(G.."/"):gmatch("([^/]*)/")do table.insert(I,J)end;return H,I end;local function K(J)local L=J:lower()if not L:match(E)then error("EINVAL: illegal characters in path component: "..J,3)end;if L==".meta"then error("EINVAL: reserved path component: .meta",3)end end;function b.splitPath(G)local M=string.split(G,"/")while table.indexOf(M,"")~=-1 do table.remove(M,table.indexOf(M,""))end;return M end;local function N(O)local P,Q=nil,nil;for R,S in pairs(b.mounts)do local T=S~="/"and S:sub(-1)=="/"and S:sub(1,-2)or S;if O==T or T=="/"and O:sub(1,1)=="/"or O:sub(1,#T+1)==T.."/"then if not P or#T>#P then P=T;Q=R end end end;if not Q then error("ENODEV")end;local U=O:sub(#P+1)if U==""then U="/"end;return b.disks[Q],U end;b._parseMetafile=g;local function V(W,X,Y)if Y==".meta"then error("EACCES: Cannot open metafile")end;local S;if X=="/"then S=".meta"else local j=X:gsub("^/+","")S=j.."/.meta"end;local Z,_=pcall(function()return W:open(S,"r")end)if not Z or not _ then return nil end;local h=_.read(65535)if _.close then _.close()end;if h and#h>0 and h:byte(1)~=c then local a0=u(g(h))local a1,a2=pcall(function()return W:open(S,"w")end)if a1 and a2 then a2.write(a0)if a2.close then a2.close()end end;h=a0 end;local a3=g(h)return a3[Y]end;local a4=16;local function a5(G,a6,a7)a7=a7 or 0;if a7>a4 then error("ELOOP")end;local a8=a.currentTask;local a9=a8 and(a8.euid or a8.uid)or a.uid;local aa=a8 and a8.groups or a.groups or{}local ab=a8 and a8.root or"/"local ac=a8 and a8.cwd or"/"if ab~="/"and ab:sub(-1)=="/"then ab=ab:sub(1,-2)end;local function ad(ae)if a9==0 then return true end;if not ae then return true end;local af=ae.perms;if a9==ae.owner and d(af,9)then return true end;if ae.group then for ag,ah in ipairs(aa)do if ah==ae.group and d(af,8)then return true end end end;return d(af,7)end;local H,I=F(G)local ai={}if H then ai={}else for aj in ac:gmatch("[^/]+")do table.insert(ai,aj)end end;local ak=1;while ak<=#I do local J=I[ak]ak=ak+1;J=J:match("^%s*(.-)%s*$")if J==""or J=="."then elseif J==".."then local al="/"..table.concat(ai,"/")local am={}if ab~="/"then for aj in ab:gmatch("[^/]+")do table.insert(am,aj)end end;if#ai<=#am then ai={}for ag,aj in ipairs(am)do table.insert(ai,aj)end else local an=ai[#ai]local ao="/"..table.concat(ai,"/",1,#ai-1)if ao=="/"then ao="/"end;local ap,aq,ar=pcall(N,ao==""and"/"or ao)if ap and aq then local ae=V(aq,ar,an)if ae then if ae.etype~=0x00 then error("ENOTDIR: not a directory: "..al)end;if not ad(ae)then error("EACCES: permission denied traversing "..al)end else local as,at,au=pcall(N,al)if as and at then local av=at:type(au)if av~=nil and av~="directory"then error("ENOTDIR: not a directory: "..al)end end end end;table.remove(ai)end else K(J)local aw=J:lower()local ax="/"..table.concat(ai,"/")local ap,aq,ar=pcall(N,ax=="/"and"/"or ax)local ae=nil;if ap and aq then ae=V(aq,ar,aw)end;local ay=ak>#I;if ae and ae.etype==0x01 then if ay and a6 then table.insert(ai,aw)else a7=a7+1;if a7>a4 then error("ELOOP")end;local az=ae.cmeta;if not az or az==""then error("ENOENT: empty symlink target")end;local aA,aB=F(az)if aA then ai={}if ab~="/"then for aj in ab:gmatch("[^/]+")do table.insert(ai,aj)end end end;local aC={}for aD=1,ak-2 do table.insert(aC,I[aD])end;local aE=#aC+1;for ag,aF in ipairs(aB)do table.insert(aC,aF)end;for aD=ak,#I do table.insert(aC,I[aD])end;I=aC;ak=aE end else table.insert(ai,aw)if not ay then local aG="/"..table.concat(ai,"/")local as,at,au=pcall(N,aG)if as and at then local av=at:type(au)if av~=nil and av~="directory"then error("ENOTDIR: not a directory: "..aG)end end;if not ad(ae)then error("EACCES: permission denied traversing "..aG)end end end end end;local aH="/"..table.concat(ai,"/")if ab~="/"then if aH~=ab and aH:sub(1,#ab+1)~=ab.."/"then aH=ab end end;return aH end;local function aI(G)local a8=a.currentTask;local ac=a8 and a8.cwd or"/"local ab=a8 and a8.root or"/"if ab~="/"and ab:sub(-1)=="/"then ab=ab:sub(1,-2)end;local H,I=F(G)local ai={}if not H then for aj in ac:gmatch("[^/]+")do table.insert(ai,aj)end end;local am={}if ab~="/"then for aj in ab:gmatch("[^/]+")do table.insert(am,aj)end end;for ag,J in ipairs(I)do J=J:match("^%s*(.-)%s*$")if J==""or J=="."then elseif J==".."then if#ai>#am then table.remove(ai)end else table.insert(ai,J:lower())end end;local aH="/"..table.concat(ai,"/")if ab~="/"then if aH~=ab and aH:sub(1,#ab+1)~=ab.."/"then aH=ab end end;return aH end;local function aJ(G,a6)local aK=a5(G,a6)local W,U=N(aK)if a.config.logPathResolution then a.log("resolvePath '"..G.."' -> '"..aK.."' diskPath '"..U.."'")end;return W,U,aK end;local function aL(G,a6)local aK=a5(G,a6)if aK=="/"then return{etype=0x00,owner=0,group=0,perms=62,cmeta=""}end;local aM=aK;while true do local aN,n=aM:match("^(.*)/([^/]+)$")if not aN or aN==""then aN="/"end;local W,X=N(aN)local ae=V(W,X,n)if ae then return ae end;if aN=="/"or aM=="/"then break end;aM=aN end;return{etype=0x00,owner=0,group=0,perms=63,cmeta=""}end;local function aO(G,n,ae,a6)local aK=a5(G,a6)local W,U=N(aK)local S;if U=="/"then S=".meta"else S=U:gsub("^/+","").."/.meta"end;local aP={}local aQ,aR=pcall(function()return W:open(S,"r")end)if aQ and aR then local h=aR.read(65535)if aR.close then aR.close()end;aP=g(h)end;aP[n]=ae;local _=W:open(S,"w")_.write(u(aP))if _.close then _.close()end end;b.P={OWNER_R=1*2^5,OWNER_W=1*2^4,OWNER_X=1*2^9,GROUP_R=1*2^3,GROUP_W=1*2^2,GROUP_X=1*2^8,WORLD_R=1*2^1,WORLD_W=1*2^0,WORLD_X=1*2^7,SUID=1*2^6}local aS=b.P;b.PERM={RW_R_R=aS.OWNER_R+aS.OWNER_W+aS.GROUP_R+aS.WORLD_R,RWX_RX=aS.OWNER_R+aS.OWNER_W+aS.OWNER_X+aS.GROUP_R+aS.GROUP_X+aS.WORLD_R+aS.WORLD_X,RW_R__=aS.OWNER_R+aS.OWNER_W+aS.GROUP_R,RW____=aS.OWNER_R+aS.OWNER_W,RWXR__=aS.OWNER_R+aS.OWNER_W+aS.OWNER_X+aS.GROUP_R+aS.WORLD_R,SUID_755=aS.SUID+aS.OWNER_R+aS.OWNER_W+aS.OWNER_X+aS.GROUP_R+aS.GROUP_X+aS.WORLD_R+aS.WORLD_X,RWXRWXRWX=aS.OWNER_R+aS.OWNER_W+aS.OWNER_X+aS.GROUP_R+aS.GROUP_W+aS.GROUP_X+aS.WORLD_R+aS.WORLD_W+aS.WORLD_X}local function aT(v,aU)local a8=a.currentTask;local a9=a8 and a8.euid or a8 and a8.uid or a.uid;local aa=a8 and a8.groups or a.groups or{}if a9==0 then return true end;local af=v.perms;if aU=="x"then if a9==v.owner and d(af,9)then return true end;if v.group then for ag,ah in ipairs(aa)do if ah==v.group and d(af,8)then return true end end end;if d(af,7)then return true end;error("EACCES")end;local aV={r={owner=5,group=3,everyone=1},w={owner=4,group=2,everyone=0},a={owner=4,group=2,everyone=0}}local x=aV[aU]if not x then error("EINVAL")end;if a9==v.owner and d(af,x.owner)then return true end;if v.group then for ag,ah in ipairs(aa)do if ah==v.group and d(af,x.group)then return true end end end;if d(af,x.everyone)then return true end;error("EACCES")end;local function aW(G)G=aI(G)if G~="/"and G:sub(-1)=="/"then G=G:sub(1,-2)end;return G end;local aX={"open","type","list","attributes","fileExists","makeDirectory","remove"}local function aY(W)for ag,n in ipairs(aX)do if type(W[n])~="function"then error("Invalid disk: missing method '"..n.."'")end end end;local aZ=0;local function a_(a8)local b0=0;while a8.fd[b0]do b0=b0+1 end;if b0>=a.config.maxFilesPerTask then error("ENFILE")end;return b0 end;local function b1()if aZ>=a.config.maxOpenFiles-16 then error("ENFILE")end end;local function b2(b3,aU,G,v,b4)return{handle=b3,mode=aU,path=G,meta=v,type=b4,refcount=1}end;function b.newfd(b5)local b0=a_(a.currentTask)a.currentTask.fd[b0]=b5;return b0 end;function b.mount(az,b6)local b7=a.currentTask and(a.currentTask.euid or a.currentTask.uid)or a.uid;if b7~=0 then error("EPERM")end;if not az then error("EINVAL")end;az=aW(az)local b8,G=aJ(az)if not b8:directoryExists(G)then b8:makeDirectory(G)end;if b8:type(az)~="directory"then error("EINVAL")end;local W,R;if type(b6)=="string"then W=a.disks[b6]if not W then error("ENODEV")end;aY(W)R=b6 elseif type(b6)=="table"then aY(b6)W=b6;R=W.address;b.disks[R]=W else error("EINVAL")end;if b.mounts[R]then error("EBUSY")end;for ag,S in pairs(b.mounts)do if S==az then error("EBUSY")end end;b.mounts[R]=az;return true end;function b.umount(az)local b7=a.currentTask and(a.currentTask.euid or a.currentTask.uid)or a.uid;if b7~=0 then error("EPERM")end;if not az then error("EINVAL")end;az=aW(az)for R,S in pairs(b.mounts)do if S==az then if R=="$"then error("EBUSY")end;b.mounts[R]=nil;return true end end;error("EINVAL")end;function b.open(G,aU)b1()local a8=a.currentTask;local b0=a_(a8)local W,U=aJ(G)if not W then error("NODISK")end;if(aU=="w"or aU=="a")and W:isReadOnly()then error("ERDONLY")end;if a.unixSockets[aI(G)]then local v=a.unixSockets[aI(G)].meta;if a.uid~=0 or a.uid~=v.owner then local aa=a8 and a8.groups or a.groups or{}local b9=false;for ag,ah in ipairs(aa)do if ah==v.group then b9=true end end;if not b9 then error("EACCES")end end;a8[b0]=a.unixSockets[aI(G)]return b0 end;local v=aL(G)local ba=(aU=="w"or aU=="a")and not W:fileExists(U)aT(v,aU=="r"and"r"or"w")local b3;if W:type(U)~="directory"then b3=W:open(U,aU)if type(b3)~="table"then error("ENFILE")end end;if ba then local a9=a8 and(a8.euid or a8.uid)or a.uid;local bb=a8 and a8.gid or 0;local bc=aI(G)local aN=bc:match("^(.*)/[^/]+$")or"/"if aN==""then aN="/"end;local n=bc:match("[^/]+$")if n then local ae={etype=0x00,owner=a9,group=bb,perms=b.PERM.RW_R_R,cmeta=""}pcall(aO,aN,n,ae,false)v=ae end end;local bd=b2(b3,aU,G,v,W:type(U))if aU=="r"and d(v.perms,6)then bd.suid_owner=v.owner end;if W.isvirt then bd.isvirt=true end;a8.fd[b0]=bd;if not W.isvirt then aZ=aZ+1 end;return b0 end;function b.read(b0,be)local bf=a.currentTask.fd[b0]if not bf or not bf.handle or not bf.handle.read then error("EBADF")end;return bf.handle.read(be or 1)or""end;function b.write(b0,bg)local bf=a.currentTask.fd[b0]if not bf or not bf.handle or not bf.handle.write then error("EBADF")end;return bf.handle.write(bg)end;function b.pread(b0,be,bh)local bf=a.currentTask.fd[b0]if not bf or not bf.handle or not bf.handle.read or not bf.handle.seek then error("EBADF")end;bf.handle.seek("set",bh)return bf.handle.read(be or 1)or""end;function b.pwrite(b0,bg,bh)local bf=a.currentTask.fd[b0]if not bf or not bf.handle or not bf.handle.write or not bf.handle.seek then error("EBADF")end;bf.handle.seek("set",bh)return bf.handle.write(bg)end;function b.lseek(b0,bh,bi)local bf=a.currentTask.fd[b0]if not bf or not bf.handle or not bf.handle.seek then error("EBADF")end;return bf.handle.seek(bi or"set",bh)end;function b.fsync(b0)local bf=a.currentTask.fd[b0]if not bf or not bf.handle or not bf.handle.flush then error("EBADF")end;if bf.mode~="w"and bf.mode~="a"then error("EBADF")end;bf.handle.flush()end;function b.close(b0)local a8=a.currentTask;local bf=a8.fd[b0]if not bf then error("EBADF")end;if not a8.fd[b0].isvirt then aZ=aZ-1 end;a8.fd[b0]=nil;bf.refcount=bf.refcount-1;if bf.refcount<=0 and bf.handle and bf.handle.close then bf.handle.close()end end;function b.sendfile(bj,bk,be)local bl=a.currentTask.fd[bk]local bm=a.currentTask.fd[bj]if not bl or not bm then error("EBADF")end;if not bl.handle.read or not bm.handle.write then error("EBADF")end;local bn=bl.handle.read(be or 1024)if not bn or bn==""then return end;return bm.handle.write(bn)end;function b.stat(G)local bo;local v;if v.etype==0x02 then bo={size=0,modified=0,created=0}else local W,U=aJ(G)v=aL(G)local Z;Z,bo=pcall(W.attributes,W,U)if not Z then bo={size=0,modified=0,created=0}end end;return{size=bo.size,modified=bo.modified,created=bo.created,owner=v.owner,group=v.group,perms=v.perms,etype=v.etype,xattr=v.cmeta}end;function b.lstat(G)local v=aL(G,true)local bo;if v.etype==0x01 or v.etype==0x02 then bo={size=0,modified=0,created=0}else local W,U=aJ(G,true)local Z,bp=pcall(W.attributes,W,U)bo=Z and bp or{size=0,modified=0,created=0}end;return{size=bo.size,modified=bo.modified,created=bo.created,owner=v.owner,group=v.group,perms=v.perms,etype=v.etype,xattr=v.etype==0x01 and""or v.cmeta,symlink_target=v.etype==0x01 and v.cmeta or nil}end;function b.fstat(b0)local bf=a.currentTask.fd[b0]if not bf then error("EBADF")end;local bo;if bf.meta.etype==0x02 then bo={size=0,modified=0,created=0}else local W,U=aJ(bf.path,true)local Z,bp=pcall(W.attributes,W,U)bo=Z and bp or{size=0,modified=0,created=0}end;return{size=bo.size,modified=bo.modified,created=bo.created,owner=bf.meta.owner,group=bf.meta.group,perms=bf.meta.perms,etype=bf.meta.etype,xattr=bf.meta.cmeta}end;function b.listdir(G)local W,U=aJ(G)local v=aL(G)aT(v,"r")if W:type(U)~="directory"then error("ENOTDIR")end;local bq=W:list(U)local br={}local w={}for ag,bs in ipairs(bq)do if bs~=".meta"then br[bs]=true;table.insert(w,bs)end end;for bt,bs in pairs(a.unixSockets)do local j=aI(G)if bt:match("^(.*)/[^/]+$")==j then br[bs.name]=true;table.insert(w,bs.name)end end;local S;if U=="/"then S=".meta"else S=U:gsub("^/+","").."/.meta"end;local bu,bv=pcall(function()return W:open(S,"r")end)if bu and bv then local h=bv.read(65535)if bv.close then bv.close()end;local a3=g(h)for n,ae in pairs(a3)do if ae.etype==0x01 and not br[n]then table.insert(w,n)end end end;return w end;function b.mkdir(G)local bc=aI(G)local aN=bc:match("^(.*)/[^/]+$")or"/"if aN==""then aN="/"end;local bw=aL(aN)aT(bw,"w")local W,U=aJ(G)if W:isReadOnly()then error("ERDONLY")end;W:makeDirectory(U)local a8=a.currentTask;local a9=a8 and(a8.euid or a8.uid)or a.uid;local bb=a8 and a8.gid or 0;local n=bc:match("[^/]+$")if n then local ae={etype=0x00,owner=a9,group=bb,perms=b.PERM.RWX_RX,cmeta=""}pcall(aO,aN,n,ae,false)end end;function b.remove(G)local bc=a5(G,true)local aN=bc:match("^(.*)/[^/]+$")or"/"if aN==""then aN="/"end;local bw=aL(aN)aT(bw,"w")local v=aL(G,true)if a.unixSockets and a.unixSockets[aI(G)]then if a.uid~=0 then if a.unixSockets[aI(G)].meta.owner~=a.uid then error("EACCES")end end;a.unixSockets[aI(G)]=nil end;if v.etype==0x01 then local bc=a5(G,true)local aN=bc:match("^(.*)/[^/]+$")or"/"if aN==""then aN="/"end;local n=bc:match("[^/]+$")local W,X=N(aN)if W:isReadOnly()then error("ERDONLY")end;local S;if X=="/"then S=".meta"else S=X:gsub("^/+","").."/.meta"end;local aQ,aR=pcall(function()return W:open(S,"r")end)local a3={}if aQ and aR then local h=aR.read(65535)if aR.close then aR.close()end;a3=g(h)end;a3[n]=nil;local bx=W:open(S,"w")bx.write(u(a3))if bx.close then bx.close()end else local W,U=aJ(G)if W:isReadOnly()then error("ERDONLY")end;W:remove(U)end end;function b.symlink(az,by)if type(az)~="string"or type(by)~="string"then error("EINVAL")end;local bc=aI(by)local aN=bc:match("^(.*)/[^/]+$")or"/"local W=N(by)if W:isReadOnly()then error("ERDONLY")end;if aN==""then aN="/"end;local n=bc:match("[^/]+$")if not n then error("EINVAL")end;local bw=aL(aN)aT(bw,"w")local a8=a.currentTask;local a9=a8 and(a8.euid or a8.uid)or a.uid;local bb=a8 and a8.gid or a.gid or 0;local ae={etype=0x01,owner=a9,group=bb,perms=b.PERM.RWXRWXRWX,cmeta=az}local Z,bz=pcall(aO,aN,n,ae,false)if not Z then error(bz)end end;function b.readlink(G)local v=aL(G,true)if v.etype~=0x01 then error("EINVAL")end;return v.cmeta end;function b.access(G,aU)local v;if a.unixSockets[aI(G)]then v=a.unixSockets[aI(G)].meta else v=aL(G)end;for ak=1,#aU do aT(v,aU:sub(ak,ak))end;return true end;local function bA(G,bB,a6)local aK=a5(G,a6)local bc=aK;local aN=bc:match("^(.*)/[^/]+$")or"/"local W=N(G)if W:isReadOnly()then error("ERDONLY")end;if aN==""then aN="/"end;local n=bc:match("[^/]+$")if not n then error("EINVAL")end;local W,bC=N(aN)local S;if bC=="/"then S=".meta"else S=bC:gsub("^/+","").."/.meta"end;local aP={}local bD,bE=pcall(function()return W:open(S,"r")end)if bD and bE then local h=bE.read(65535)if bE.close then bE.close()end;aP=g(h)end;local ae=aP[n]or{etype=0,owner=0,group=0,perms=63,cmeta=""}bB(ae)aP[n]=ae;local _=W:open(S,"w")_.write(u(aP))if _.close then _.close()end end;function b.chmod(G,r)if a.unixSockets[aI(G)]then error("EINVAL")end;local W=N(G)if W:isReadOnly()then error("ERDONLY")end;local v=aL(G)local a9=a.currentTask and(a.currentTask.euid or a.currentTask.uid)or a.uid;if a9~=0 and a9~=v.owner then error("EACCES")end;bA(G,function(bF)bF.perms=r end)end;function b.fchmod(b0,r)local bf=a.currentTask.fd[b0]if not bf then error("EBADF")end;if bf.etype==0x02 then error("EINVAL")end;b.chmod(bf.path,r)end;function b.chown(G,bG,ah)if a.unixSockets[aI(G)]then error("EINVAL")end;local W=N(G)if W:isReadOnly()then error("ERDONLY")end;local b7=a.currentTask and(a.currentTask.euid or a.currentTask.uid)or a.uid;if b7~=0 then error("EPERM")end;bA(G,function(bF)bF.owner=bG;bF.group=ah end)end;function b.fchown(b0,bG,ah)local bf=a.currentTask.fd[b0]if not bf then error("EBADF")end;if bf.etype==0x02 then error("EINVAL")end;b.chown(bf.path,bG,ah)end;function b.exists(G)local v=aL(G,true)if v.etype==0x01 then return true end;local Z,W,U=pcall(aJ,G)if not Z then return false end;if W:type(U)then return true else return false end end;function b.type(G)local v=aL(G,true)if v.etype==0x01 then return"symlink"end;if a.unixSockets[aI(G)]then return"socket"end;local Z,W,U=pcall(aJ,G)if not Z then return nil end;return W:type(U)end;function b.getcwd()return a.currentTask.cwd end;function b.chdir(G)if b.type(G)~="directory"then error("ENOTDIR")end;a.currentTask.cwd=aI(G)end;function b.chroot(G)local a9=a.currentTask and(a.currentTask.euid or a.currentTask.uid)or a.uid;if a9~=0 then error("EPERM")end;if b.type(G)~="directory"then error("ENOTDIR")end;local bc=aI(G)a.currentTask.root=bc;a.currentTask.cwd=bc end;function b.dup(bH)local a8=a.currentTask;local bf=a8.fd[bH]if not bf then error("EBADF")end;b1()local bI=a_(a8)bf.refcount=bf.refcount+1;a8.fd[bI]=bf;aZ=aZ+1;return bI end;function b.dup2(bH,bI)local a8=a.currentTask;local bf=a8.fd[bH]if not bf then error("EBADF")end;if bI<0 or bI>=a.config.maxFilesPerTask then error("EBADF")end;if bH==bI then return bI end;if a8.fd[bI]then b.close(bI)end;b1()bf.refcount=bf.refcount+1;a8.fd[bI]=bf;aZ=aZ+1;return bI end;function b.devctl(b0,bJ,...)if not a.currentTask.fd[b0]then error("EBADF")end;if not a.currentTask.fd[b0].handle[bJ]then error("EINVAL")end;return a.currentTask.fd[b0].handle[bJ](...)end;b.resolveMount=N;local bK=a.syscalls;bK["open"]=b.open;bK["close"]=b.close;bK["read"]=b.read;bK["write"]=b.write;bK["pread"]=b.pread;bK["pwrite"]=b.pwrite;bK["lseek"]=b.lseek;bK["fsync"]=b.fsync;bK["sendfile"]=b.sendfile;bK["stat"]=b.stat;bK["lstat"]=b.lstat;bK["fstat"]=b.fstat;bK["mkdir"]=b.mkdir;bK["remove"]=b.remove;bK["listdir"]=b.listdir;bK["chmod"]=b.chmod;bK["fchmod"]=b.fchmod;bK["chown"]=b.chown;bK["fchown"]=b.fchown;bK["exists"]=b.exists;bK["type"]=b.type;bK["mount"]=b.mount;bK["umount"]=b.umount;bK["getcwd"]=b.getcwd;bK["chdir"]=b.chdir;bK["chroot"]=b.chroot;bK["dup"]=b.dup;bK["dup2"]=b.dup2;bK["devctl"]=b.devctl;bK["symlink"]=b.symlink;bK["readlink"]=b.readlink;bK["access"]=b.access;bK["fget_suid"]=function(b0)local bd=a.currentTask and a.currentTask.fd[b0]return bd and bd.suid_owner or nil end;a.log("VFS module loaded") diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/11_require.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/11_require.kmod new file mode 100644 index 0000000..e232d03 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/11_require.kmod @@ -0,0 +1 @@ +local a=...local b={}a.searchpaths={"/lib/?.lua","/lib/?","/usr/lib/?.lua","/usr/lib/?","/usr/local/lib/?.lua","/usr/local/lib/?","?.lua","?"}function require(c,...)if b[c]then return b[c]end;local d=c:gsub("%.","/")local e={}for f,g in ipairs(a.searchpaths)do local h=string.replace(g,"?",d)if h:sub(1,1)~="/"then h=a.currentTask.cwd..h end;if a.vfs.exists(h)then if a.vfs.type(h)=="directory"then h=h.."/init"end;if a.vfs.exists(h)then local i=a.vfs.open(h,"r")local j=a.vfs.read(i,1024*1024*4)a.vfs.close(i)return assert(load(j,h,"t",a._U))(...)else table.insert(e,h)end else table.insert(e,h)end end;error("Module not found: "..c.." (searched paths: "..table.concat(e,", ")..")")end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/12_devfs.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/12_devfs.kmod new file mode 100644 index 0000000..83dbc7f --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/12_devfs.kmod @@ -0,0 +1 @@ +local a=...local b={}local c={}b.address="devfs0000"b.isvirt=true;b.isReadOnly=function()return false end;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function()error("EACCES")end;b.remove=function()error("EACCES")end;b.setLabel=function()error("EACCES")end;b.getLabel=function()return"devfs"end;b.attributes=function(d)return{size=0,modified=0,created=0}end;function b:open(d,e)local f=a.vfs.splitPath(d)local g=c;for h=1,#f-1 do local i=g[f[h]]if type(i)~="table"then error("ENFILE")end;g=i end;if type(g[f[#f]])=="function"then return g[f[#f]]("open",e)end;error("ENFILE")end;function b:type(d,e)local f=a.vfs.splitPath(d)local g=c;if#f==0 then return"directory"end;for h=1,#f-1 do local i=g[f[h]]if type(i)~="table"then error("ENFILE")end;g=i end;if type(g[f[#f]])=="function"then return g[f[#f]]("type",e)end;if type(g[f[#f]])=="table"then return"directory"end;error(type(g[f[#f]]))end;function b:list(d)local f=a.vfs.splitPath(d)local g=c;if#f==0 then return table.keys(c)end;for h=1,#f-1 do local i=g[f[h]]if type(i)~="table"then error("ENOENT")end;g=i end;if type(g[f[#f]])=="table"then return table.keys(g[f[#f]])end;error("ENOENT")end;function b:fileExists(d)local j=pcall(function()return self:type(d)end)return j end;function c.random(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then return{read=function(l)local m=""for h=1,l or 1 do m=m..string.char(math.random(0,255))end;return m end}elseif e=="w"or e=="a"then return{write=function()end}else error("EACCES")end end end;function c.null(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then return{read=function(l)end}elseif e=="w"or e=="a"then return{write=function()end}else error("EACCES")end end end;function c.zero(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then return{read=function(l)local m=""for h=1,l or 1 do m=m..string.char(0)end;return m end}elseif e=="w"or e=="a"then return{write=function()end}else error("EACCES")end end end;if a.EFI:getEEPROM()then function c.eeprom(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then local n,o=1,a.EFI:getEEPROM()return{read=function(l)n=n+l;return o:sub(n-l,n)end}elseif e=="w"then if a.uid~=0 then error("EACCES")end;local p=true;return{write=function(c)if p then a.EFI:setEEPROM(c)else a.EFI:setEEPROM(a.EFI:getEEPROM()..c)end end}elseif e=="a"then if a.uid~=0 then error("EACCES")end;return{write=function(c)a.EFI:setEEPROM(a.EFI:getEEPROM()..c)end}else error("EACCES")end end end end;if a.EFI:getNvram()then function c.nvram(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then local n,q=1,a.EFI:getNvram()return{read=function(l)n=n+l;return q:sub(n-l,n)end}elseif e=="w"then if a.uid~=0 then error("EACCES")end;local p=true;return{write=function(c)if p then a.EFI:setNvram(c)else a.EFI:setNvram(a.EFI:getNvram()..c)end end}elseif e=="a"then if a.uid~=0 then error("EACCES")end;return{write=function(c)a.EFI:setNvram(a.EFI:getNvram()..c)end}else error("EACCES")end end end end;c["disk"]={}a.devfs={}a.devfs.data=c;a.devfs.proxy=b;a.disks["devfs0000"]=b diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod new file mode 100644 index 0000000..fedf534 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod @@ -0,0 +1 @@ +local a=...local b={}local c={}b.address="procfs0000"b.isvirt=true;b.isReadOnly=function()return true end;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function()error("EACCES")end;b.remove=function()error("EACCES")end;b.setLabel=function()error("EACCES")end;b.getLabel=function()return"procfs"end;b.attributes=function(d)return{size=0,modified=0,created=0}end;local function e(f,g)g=g or{}local h=g.uid or 0;local i=g.gid or 0;local j=g.perms or 0x3F;local k={}table.insert(k,string.char(0x02))for d,l in pairs(f)do local m=d;local n=#m;if n>255 then error("Filename too long (>255 bytes): "..m)end;local o=0x00;local p=""if l and l~=""then o=0x01;p=l end;local q=#p;if q>255 then error("cmeta too long (>255 bytes) for "..m)end;table.insert(k,string.char(n))table.insert(k,m)table.insert(k,string.char(o))table.insert(k,string.char(h%256,math.floor(h/256)%256))table.insert(k,string.char(i%256,math.floor(i/256)%256))table.insert(k,string.char(j%256,math.floor(j/256)%256))table.insert(k,string.char(q))if q>0 then table.insert(k,p)end end;return table.concat(k)end;local function r(s,t)return function(u,v)if u=="type"then return"character device"elseif u=="open"then if v=="r"then return{read=s}elseif v=="w"then return{write=t}end end end end;local function w(x)local y=tostring(x)local z=1;return r(function(A)z=z+A;return y:sub(z-A,z)end,function()error("EACCES")end)end;local function B(C)local D,E,F={},{},{}if C.fd[0]then D["0"]=C.fd[0].path end;for G,H in ipairs(C.fd)do D[tostring(G)]=tostring(H.path)end;for G,H in ipairs(C.siblings)do E[tostring(H.pid)]="/proc/"..tostring(H.pid)end;for G,H in ipairs(C.children)do F[tostring(H.pid)]="/proc/"..tostring(H.pid)end;return{[".meta"]=w(e({cwd=C.cwd,parent="/proc/"..tostring(C.parent.pid)})),uid=w(C.uid),comm=w(C.name),fd={[".meta"]=w(e(D))},siblings={[".meta"]=w(e(E))},children={[".meta"]=w(e(F))}}end;function b:open(d,v)local I=a.vfs.splitPath(d)local J=c;if tonumber(I[1])then local C=a.tasks[tostring(I[1])]local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("open",v)end elseif tostring(I[1])=="self"then local C=a.currentTask;local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("open",v)end else for G=1,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("open",v)end end;error("ENFILE")end;function b:type(d,v)local I=a.vfs.splitPath(d)local J=c;if#I==0 then return"directory"end;if tonumber(I[1])then local C=a.tasks[I[1]]if#I==1 then return"directory"end;local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("type",v)end;if type(J[I[#I]])=="table"then return"directory"end elseif tostring(I[1])=="self"then local C=a.currentTask;if#I==1 then return"directory"end;local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("type",v)end;if type(J[I[#I]])=="table"then return"directory"end else for G=1,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("type",v)end;if type(J[I[#I]])=="table"then return"directory"end end;error("ENOENT")end;function b:list(d)local I=a.vfs.splitPath(d)local J=c;if#I==0 then return table.merge(table.keys(c),table.keys(a.tasks),{"self"})end;if tonumber(I[1])then local C=a.tasks[I[1]]local J=B(C)if#I==1 then return table.keys(J)end;for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENOENT")end;J=y end;if type(J[I[#I]])=="table"then return table.keys(J[I[#I]])end elseif tostring(I[1])=="self"then local C=a.currentTask;local J=B(C)if#I==1 then return table.keys(J)end;for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENOENT")end;J=y end;if type(J[I[#I]])=="table"then return table.keys(J[I[#I]])end else for G=1,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENOENT")end;J=y end;if type(J[I[#I]])=="table"then return table.keys(J[I[#I]])end end;error("ENOENT")end;function b:fileExists(d)local K=pcall(function()return self:type(d)end)return K end;c.uptime=r(function()return tostring(a.EFI:getUptime())end,function()error("EACCES")end)a.procfs={}a.procfs.data=c;a.procfs.proxy=b;a.disks["procfs0000"]=b diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/12_tmpfs.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/12_tmpfs.kmod new file mode 100644 index 0000000..f60d532 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/12_tmpfs.kmod @@ -0,0 +1 @@ +local a=...local b={}local c={}b.address="tmpfs0000"b.isvirt=true;b.isReadOnly=function()return false end;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function(d,e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f do if not g[f[h]]then g[f[h]]={}elseif type(g[f[h]])~="table"then error("ENOTDIR")end;g=g[f[h]]end end;b.remove=function(d,e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f-1 do g=g[f[h]]if not g then error("ENOENT")end end;g[f[#f]]=nil end;b.setLabel=function(d,i)end;b.getLabel=function()return"tmpfs"end;b.attributes=function(d,e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f do g=g[f[h]]if not g then error("ENOENT")end end;return{size=type(g)=="string"and#g or 0,modified=0,created=0}end;function b:open(e,j)local f=a.vfs.splitPath(e)local g=c;for h=1,#f-1 do if not g[f[h]]then if j=="w"then g[f[h]]={}else error("ENOENT")end elseif type(g[f[h]])~="table"then error("ENOTDIR")end;g=g[f[h]]end;local k=f[#f]if j=="r"then if type(g[k])~="string"then error("ENOENT")end;local l=g[k]local m=1;return{read=function(n)n=n or#l;local o=l:sub(m,m+n-1)m=m+#o;return o end,close=function()end}elseif j=="w"then g[k]=""local p={}return{write=function(q)p[#p+1]=q end,close=function()g[k]=table.concat(p)end}elseif j=="a"then if type(g[k])~="string"then g[k]=""end;return{write=function(q)g[k]=g[k]..q end,close=function()end}else error("EACCES")end end;function b:type(e)local f=a.vfs.splitPath(e)local g=c;if#f==0 then return"directory"end;for h=1,#f do g=g[f[h]]if not g then return false end end;if type(g)=="table"then return"directory"end;if type(g)=="string"then return"file"end end;function b:list(e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f do g=g[f[h]]if not g then error("ENOENT")end end;if type(g)~="table"then error("ENOTDIR")end;local r={}for s,d in pairs(g)do table.insert(r,s)end;return r end;function b:fileExists(e)local t=self:type(e)return t=="file"or t=="directory"end;a.disks["tmpfs0000"]=b diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/13_loopdev.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/13_loopdev.kmod new file mode 100644 index 0000000..38573af --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/13_loopdev.kmod @@ -0,0 +1 @@ +local a=...local b=nil;local function c()if b==nil then local d,e=pcall(require,"store.deflate")b=d and e or false end;return b or nil end;local function f(g)g=math.floor(g)%4294967296;return string.char(g%256,math.floor(g/256)%256,math.floor(g/65536)%256,math.floor(g/16777216)%256)end;local function h(i,j)local k,l,m,n=i:byte(j,j+3)return(k or 0)+(l or 0)*256+(m or 0)*65536+(n or 0)*16777216 end;local o="BHFS"local p="\001"local q=1;local r="\001"local s="\002"local t="\003"local u="\255"local v={}do local k="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"for j=1,#k do v[k:sub(j,j)]=j-1 end end;local function w(i)i=i:gsub("[^A-Za-z0-9+/=]","")local x,j={},1;while j<=#i do local y=v[i:sub(j,j)]or 0;local z=v[i:sub(j+1,j+1)]or 0;local A=v[i:sub(j+2,j+2)]or 0;local B=v[i:sub(j+3,j+3)]or 0;local g=y*262144+z*4096+A*64+B;x[#x+1]=string.char(math.floor(g/65536)%256)if i:sub(j+2,j+2)~="="then x[#x+1]=string.char(math.floor(g/256)%256)end;if i:sub(j+3,j+3)~="="then x[#x+1]=string.char(g%256)end;j=j+4 end;return table.concat(x)end;local C={}local D=0;local function E(F,G)local H={address=F,isvirt=false}H.isReadOnly=function()return false end;H.spaceUsed=function()return 0 end;H.spaceTotal=function()return 0 end;H.setLabel=function()end;H.getLabel=function()return F end;local function I()local J,K="/","$"for L,M in pairs(a.vfs.mounts)do if G==M or M=="/"and G:sub(1,1)=="/"or G:sub(1,#M+1)==M.."/"then if#M>#J then J=M;K=L end end end;return a.vfs.disks[K],G:sub(#J+1)end;local function N(O)local P,Q=I()local l=(Q==""or Q=="/")and""or Q:gsub("^/+","")local R=O:gsub("^/+","")local m=(l==""and"/"..R or"/"..l.."/"..R):gsub("//+","/")local S=m:sub(2)if S==""then S="/"end;return P,S end;function H:open(O,T)local U,S=N(O)return U:open(S,T)end;function H:type(O)local U,S=N(O)return U:type(S)end;function H:list(O)local U,S=N(O)return U:list(S)end;function H:fileExists(O)local U,S=N(O)return U:fileExists(S)end;function H:attributes(O)local U,S=N(O)return U:attributes(S)end;function H:makeDirectory(O)local U,S=N(O)return U:makeDirectory(S)end;function H:remove(O)local U,S=N(O)return U:remove(S)end;return H end;local function V(F,W)local X={kind="dir",children={}}local function Y(O,Z)local _={}for R in O:gmatch("[^/]+")do _[#_+1]=R end;local a0=X;for j=1,#_ do local a1=_[j]if not a0.children then if not Z then return nil end;a0.children={}end;if not a0.children[a1]then if not Z then return nil end;a0.children[a1]={kind="dir",children={}}end;a0=a0.children[a1]end;return a0 end;local function a2(O)local a3=O:match("^(.*)/[^/]+$")or""if a3~=""then local g=Y(a3,true)if not g.children then g.children={}end end end;if W:sub(1,4)==o then local a4=9;while a4<=#W do local a5=W:sub(a4,a4)a4=a4+1;if a5==u then break end;local a6=h(W,a4)a4=a4+4;local a7=h(W,a4)a4=a4+4;local a8=h(W,a4)a4=a4+4;local O=W:sub(a4,a4+a6-1)a4=a4+a6;local a9=W:sub(a4,a4+a8-1)a4=a4+a8;local aa=a9;if a80 and w(ae)or""local g=Y(R,true)g.kind="file"g.data=aa;g.size=#aa;g.children=nil end elseif ac:sub(1,5)=="LINK "then local R,af=ac:sub(6):match("^(%S+)%s+(.+)$")if R then a2(R)local g=Y(R,true)g.kind="link"g.target=af;g.children=nil end end end end;local H={address=F,isvirt=false}H.isReadOnly=function()return false end;H.spaceTotal=function()return 1024*1024*64 end;H.spaceUsed=function()local ag=0;local function ah(g)if g.kind=="file"then ag=ag+(g.size or 0)elseif g.kind=="dir"then for ai,m in pairs(g.children or{})do ah(m)end end end;ah(X)return ag end;H.setLabel=function()end;H.getLabel=function()return F end;local function aj(O)return O:gsub("^/+",""):gsub("/+$","")end;function H:type(O)local R=aj(O)if R==""then return"directory"end;local g=Y(R)if not g then return nil end;if g.kind=="dir"then return"directory"end;return"file"end;function H:fileExists(O)local R=aj(O)if R==""then return true end;return Y(R)~=nil end;function H:list(O)local R=aj(O)local a0=R==""and X or Y(R)if not a0 or a0.kind~="dir"then return{}end;local ak={}for a1 in pairs(a0.children or{})do ak[#ak+1]=a1 end;return ak end;function H:attributes(O)local R=aj(O)local a0=R==""and X or Y(R)if not a0 then return nil end;return{size=a0.kind=="file"and(a0.size or 0)or 0,isDir=a0.kind=="dir",isReadOnly=false,created=0,modified=0}end;function H:open(O,T)local R=aj(O)local a0=Y(R)if T=="r"then if not a0 or a0.kind~="file"then error("ENOENT: "..O)end;local aa,a4=a0.data or"",1;return{read=function(g)if a4>#aa then return nil end;local al=aa:sub(a4,a4+(g or 1)-1)a4=a4+#al;return al end,readAll=function()local am=aa:sub(a4)a4=#aa+1;return am end,readLine=function()if a4>#aa then return nil end;local an=aa:find("\n",a4,true)local ac;if an then ac=aa:sub(a4,an-1)a4=an+1 else ac=aa:sub(a4)a4=#aa+1 end;return ac end,seek=function(ah,ao)ao=ao or 0;if ah=="set"then a4=ao+1 elseif ah=="cur"then a4=a4+ao elseif ah=="end"then a4=#aa+1+ao end;return a4-1 end,close=function()end}elseif T=="w"or T=="a"then local ap=T=="a"and a0 and a0.kind=="file"and{a0.data or""}or{}local aq=false;local function ar()if aq then return end;aq=true;local aa=table.concat(ap)if not a0 then a2(R)a0=Y(R,true)end;a0.kind="file"a0.data=aa;a0.size=#aa;a0.children=nil end;return{write=function(i)ap[#ap+1]=tostring(i)end,writeLine=function(i)ap[#ap+1]=tostring(i).."\n"end,flush=function()end,close=ar}else error("EINVAL: unknown mode: "..tostring(T))end end;function H:makeDirectory(O)local R=aj(O)if R==""then return end;a2(R)local g=Y(R,true)g.kind="dir"g.children=g.children or{}g.data=nil;g.size=nil end;function H:remove(O)local R=aj(O)if R==""then error("EBUSY: cannot remove root")end;local a3=R:match("^(.*)/[^/]+$")or""local a1=R:match("([^/]+)$")local as=a3==""and X or Y(a3)if as and as.children then as.children[a1]=nil end end;H._root=X;return H end;local function at(au)local ab=c()local av=ab~=nil;local aw=av and q or 0;local _={o,p,string.char(aw),"\0\0"}au=au:gsub("/$","")local ax=64;local function ay(az)local aA=a.vfs.type(az)if aA=="directory"then if az~=au then local aB=az:sub(#au+1)_[#_+1]=s;_[#_+1]=f(#aB)_[#_+1]=f(0)_[#_+1]=f(0)_[#_+1]=aB end;local d,aC=pcall(a.vfs.listdir,az)if d and aC then table.sort(aC)for ai,a1 in ipairs(aC)do ay(az:gsub("/$","").."/"..a1)end end elseif aA=="file"then local aB=az:sub(#au+1)local d,aD=pcall(a.vfs.open,az,"r")if d then local aE=""local aF,aG=pcall(a.vfs.read,aD,1024*1024)if aF then aE=aG or""end;pcall(a.vfs.close,aD)local aH=aE;if av and#aE>=ax then local aI=ab.compress(aE)if aI and#aI<#aE then aH=aI end end;_[#_+1]=r;_[#_+1]=f(#aB)_[#_+1]=f(#aE)_[#_+1]=f(#aH)_[#_+1]=aB;_[#_+1]=aH end end end;ay(au)_[#_+1]=u;return table.concat(_)end;a.syscalls["losetup"]=function(aJ,aK)if not aJ then error("EINVAL")end;local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;aJ=aJ:gsub("/$","")local F="loop"..tostring(D)D=D+1;local aA=a.vfs.type(aJ)local H,T;if not aK and aA=="directory"then H=E(F,aJ)T="bind"elseif aA=="file"or aK then if aA~="file"then error("ENOENT: not a file: "..aJ)end;local aN;local d,aD=pcall(a.vfs.open,aJ,"rb")if d then local aF,aa=pcall(a.vfs.read,aD,1024*1024*16)pcall(a.vfs.close,aD)if aF and aa then aN=aa end end;if not aN then local aF,aO=pcall(a.vfs.open,aJ,"r")if not aF then error("EIO: cannot open image: "..aJ)end;local aP,aa=pcall(a.vfs.read,aO,1024*1024*16)pcall(a.vfs.close,aO)if not aP or not aa then error("EIO: cannot read image: "..aJ)end;aN=aa end;H=V(F,aN)T="image"else error("EINVAL: path must be a directory or .hfs image file")end;a.vfs.disks[F]=H;C[F]={path=aJ,disk=H,mode=T}a.log("losetup: attached "..F.." ("..T..") -> "..aJ,"INFO")return F end;a.syscalls["lodetach"]=function(F)local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;if not C[F]then error("ENXIO")end;for K in pairs(a.vfs.mounts)do if K==F then error("EBUSY: loop device is still mounted")end end;a.vfs.disks[F]=nil;C[F]=nil;a.log("lodetach: detached "..F,"INFO")end;a.syscalls["lolist"]=function()local aQ={}for F,aR in pairs(C)do aQ[F]={path=aR.path,mode=aR.mode}end;return aQ end;a.syscalls["loimgcreate"]=function(au)local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;if not au then error("EINVAL")end;if a.vfs.type(au)~="directory"then error("ENOTDIR: "..au)end;return at(au)end;a.syscalls["loimgwrite"]=function(aS,aT)local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;if not aS or not aT then error("EINVAL")end;local d,aD=pcall(a.vfs.open,aT,"wb")if not d then d,aD=pcall(a.vfs.open,aT,"w")if not d then error("EIO: cannot write: "..tostring(aT))end end;local aF,aU=pcall(a.vfs.write,aD,aS)pcall(a.vfs.close,aD)if not aF then error("EIO: write failed: "..tostring(aU))end end;a.log("Loop device driver loaded (bind + BHFS binary image + legacy HFS compat)") diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/19_fstab.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/19_fstab.kmod new file mode 100644 index 0000000..30170a8 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/19_fstab.kmod @@ -0,0 +1 @@ +local a=...local function b(c)local d,e=1,#c;while d<=e and(c:sub(d,d)==" "or c:sub(d,d)=="\t")do d=d+1 end;while e>=d and(c:sub(e,e)==" "or c:sub(e,e)=="\t"or c:sub(e,e)=="\n"or c:sub(e,e)=="\r")do e=e-1 end;if d>e then return""end;return c:sub(d,e)end;for f,g in ipairs(string.split(a.fstab,"\n"))do g=b(g)if g~=""and g:sub(1,1)=="U"then local h;for i=3,#g do if g:sub(i,i)==";"then h=i;break end end;if not h or h==3 then a.log("Invalid fstab line: "..g.." ... Skipping.","WARN",0xFF8800)else local j=g:sub(3,h-1)local k=b(g:sub(h+1))a.log("Mounted "..j.." to "..k)if j~="$"then a.vfs.mount(k,j)end end end end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod new file mode 100644 index 0000000..88b1567 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/20_signals.kmod @@ -0,0 +1 @@ +local a=...local b={}a.signal=b;function b.sigsend(c,d)if d<0 or d>256 then error("EINVAL")end;local e=a.tasks[tostring(c)]if not e then error("ENOENT")end;if not e.sigq then return end;e.sigq[#e.sigq+1]=d end;function b.sigcatch(f)local e=a.currentTask;e.sigh=f;if not e.sigq then e.sigq={}end;local g={error="",active=true}if e.sigd then e.sigd.active=false end;e.sigd=g;return g end;function b.sigignore()local e=a.currentTask;e.sigh=nil;e.sigq=nil;if e.sigd then e.sigd.active=false end;e.sigd=nil end;local h=a.syscalls;h["sigsend"]=b.sigsend;h["sigcatch"]=b.sigcatch;h["sigignore"]=b.sigignore diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod new file mode 100644 index 0000000..7d41d37 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod @@ -0,0 +1 @@ +local a=...local b={}b.handlers={}a.socket=b;function b.registerProtocal(c,d)b.handlers[c]=d end;function b.socket()local e=a.vfs.P;local f=a.newFifo()local g=false;a.vfs.newfd({handle={read=function()if not g then error("ECCON")end;return f.read()end,write=function()if not g then error("ECCON")end;return f.write()end,close=function()g=true end},type="socket",refcount=1,meta={owner=a.currentTask.uid,group=a.currentTask.uid,etype=2,perms=e.OWNER_R+e.OWNER_W+e.GROUP_R+e.GROUP_W},isvirt=true})end;function b.connect(h,i)end;function b.listen(h,j)end;a.log("Loaded socket module") diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/21_unixsockets.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/21_unixsockets.kmod new file mode 100644 index 0000000..a8d1eba --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/21_unixsockets.kmod @@ -0,0 +1 @@ +local a=...a.unixSockets={} diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod new file mode 100644 index 0000000..8b69866 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod @@ -0,0 +1 @@ +local a={...}local b=a[1]b._G=_G;local function c(d)return setmetatable({},{__index=function(e,f)local g=d[f]if type(g)=="table"then return c(g)end;return g end,__newindex=function(h,i,j)if b.config.allowGlobalOverwrites or b.allowGlobalOverwrites then rawset(d,i,j)return end;error("Attempt to modify global variable '"..i.."'",2)end,__pairs=function(self)local function k(e,f)local l,g=next(d,f)if type(g)=="table"then g=c(g)end;return l,g end;return k,self,nil end,__ipairs=function()local m=0;return function()m=m+1;local g=d[m]if g==nil then return end;if type(g)=="table"then g=c(g)end;return m,g end end,__len=function()return#d end,__metatable=false})end;local n=load;b._U=c(b._G)b._U._G=b._U;b._U.load=function(o,p,q,r)return n(o,p,q,r or b._U)end;function b.freshUserEnv()local s={}s.syscall=_makeSyscallProxy()local t=setmetatable(s,{__index=b._U,__newindex=function(e,i,j)rawset(s,i,j)end,__metatable=false})s._G=t;s.load=function(o,p,q,r)return n(o,p,q,r or t)end;return t end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/40_auth.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/40_auth.kmod new file mode 100644 index 0000000..c05bf52 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/40_auth.kmod @@ -0,0 +1 @@ +local a=...local b={}a.auth=b;local function c(d)local e=a.vfs.open(d,"r")if not e then error("Failed to open file: "..d)end;local f=a.vfs.read(e,1024000)a.vfs.close(e)return f end;local function g(d,f)local e=a.vfs.open(d,"w")if not e then error("Failed to open file for writing: "..d)end;a.vfs.write(e,f)a.vfs.close(e)end;local h;do local i=2^32;local function j(k)return k%i end;local function l(k)k=j(k)local m={}for n=0,31 do local o=k%2;m[n]=o;k=(k-o)/2 end;return m end;local function p(m)local k,q=0,1;for n=0,31 do if m[n]==1 then k=k+q end;q=q*2 end;return j(k)end;local function r(...)local s={...}if#s==0 then return 0 end;local t=l(s[1])for n=2,#s do local o=l(s[n])for u=0,31 do t[u]=(t[u]==1 or o[u]==1)and 1 or 0 end end;return p(t)end;local function v(...)local s={...}if#s==0 then return 0 end;local t=l(s[1])for n=2,#s do local o=l(s[n])for u=0,31 do t[u]=t[u]~=o[u]and 1 or 0 end end;return p(t)end;local function w(k,x)return j(j(k)*2^x)end;local function y(k,x)return math.floor(j(k)/2^x)end;local function z(k,x)return r(y(k,x),w(k,32-x))end;local A={0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19}local B={{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 C(D,E,o,F,G,k,H)D[E]=(D[E]+D[o]+k)%i;D[G]=z(v(D[G],D[E]),16)D[F]=(D[F]+D[G])%i;D[o]=z(v(D[o],D[F]),12)D[E]=(D[E]+D[o]+H)%i;D[G]=z(v(D[G],D[E]),8)D[F]=(D[F]+D[G])%i;D[o]=z(v(D[o],D[F]),7)end;local function I(J,K,m,L)local D={}for n=1,8 do D[n]=J[n]end;for n=1,8 do D[n+8]=A[n]end;D[13]=v(D[13],m)if L then D[15]=v(D[15],0xFFFFFFFF)end;local M={}for n=0,15 do local q=n*4+1;M[n]=(K:byte(q)or 0)+(K:byte(q+1)or 0)*0x100+(K:byte(q+2)or 0)*0x10000+(K:byte(q+3)or 0)*0x1000000 end;for N=1,10 do local O=B[N]C(D,1,5,9,13,M[O[1]],M[O[2]])C(D,2,6,10,14,M[O[3]],M[O[4]])C(D,3,7,11,15,M[O[5]],M[O[6]])C(D,4,8,12,16,M[O[7]],M[O[8]])C(D,1,6,11,16,M[O[9]],M[O[10]])C(D,2,7,12,13,M[O[11]],M[O[12]])C(D,3,8,9,14,M[O[13]],M[O[14]])C(D,4,5,10,15,M[O[15]],M[O[16]])end;for n=1,8 do J[n]=v(J[n],D[n],D[n+8])end end;function h(P,Q)Q=Q or""local J={}for n=1,8 do J[n]=A[n]end;local R=32;J[1]=v(J[1],0x01010000+w(#Q,8)+R)local m=0;if#Q>0 then local K=Q..string.rep("\0",64-#Q)m=#Q;I(J,K,m,false)end;for n=1,#P,64 do local K=P:sub(n,n+63)if#K<64 then K=K..string.rep("\0",64-#K)end;m=m+math.min(64,#P-n+1)I(J,K,m,n+64>#P)end;local S=""for n=1,8 do S=S..string.format("%08x",J[n])end;return S end end;if not h then error("Failed to load blake2s")end;if not a.vfs.exists("/etc/pam.d/secret")then a.log("PAM SECRET REGENERATING PLEASE USE ROOT","WARN",0xFF8800)local Q=""for n=1,256 do Q=Q..string.char(math.random(0,255))end;local T=a.vfs.open("/etc/pam.d/secret","w")a.vfs.write(T,Q)a.vfs.close(T)end;local U=c("/etc/pam.d/secret")local function V()return toHex(math.random(0,2^32))end;local function W(X,Y)local Q=U..Y;return h(X,Q)end;local Z=c("/etc/passwd")local _=c("/etc/shadow")local a0=string.split(Z,"\n")local a1=string.split(_,"\n")local a2,a3={},{}for a4,D in ipairs(a0)do local a5=string.split(D,":")if a5[1]and a5[1]~=""then a2[#a2+1]=a5 end end;for a4,D in ipairs(a1)do local a5=string.split(D,":")if a5[1]and a5[1]~=""then a3[#a3+1]=a5 end end;for a4,D in ipairs(a2)do local a6=tonumber(D[1])if a6 then a.users[a6]=D[3]end end;a.passwd=a2;local function a7()local a8={}for a4,D in ipairs(a2)do a8[#a8+1]=table.concat(D,":")end;g("/etc/passwd",table.concat(a8,"\n"))end;local function a9()local a8={}for a4,D in ipairs(a3)do a8[#a8+1]=table.concat(D,":")end;g("/etc/shadow",table.concat(a8,"\n"))end;local function aa(a6)for a4,D in ipairs(a2)do if tonumber(D[1])==a6 then return D end end;return nil end;local function ab(a6)for a4,D in ipairs(a3)do if tonumber(D[1])==a6 then return D end end;return nil end;local function ac(ad)for a4,D in ipairs(a2)do if D[3]==ad then return D end end;return nil end;local function ae()local af=999;for a4,D in ipairs(a2)do local a6=tonumber(D[1])if a6 and a6>=1000 and a6>af then af=a6 end end;return af+1 end;function b.login(a6,X)if type(a6)~="number"or type(X)~="string"then return nil,"Authentication failure"end;local ag=aa(a6)if not ag then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local ah=ab(a6)if not ah then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local Y=ah[2]local ai=ah[3]local aj=W(X,Y)if aj~=ai then return nil,"Authentication failure"end;a.currentUID=a6;local ak=a.currentTask;if ak then ak.uid=a6;ak.euid=a6;ak.gid=tonumber(ag[2])or a6;ak.egid=tonumber(ag[2])or a6 end;a.log("AUTH: login uid="..tostring(a6).." ("..aa(a6)[3]..")")return true end;function b.setPassword(a6,al)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.currentProcess and a.currentProcess.euid or a.currentUID or 0;if am~=0 and am~=a6 then return nil,"Permission denied"end;if type(al)~="string"or#al==0 then return nil,"Password may not be empty"end;if#al<6 then return nil,"Password is too short (minimum 6 characters)"end;local Y=V()local an=W(al,Y)local ah=ab(a6)if ah then ah[2]=Y;ah[3]=an else a3[#a3+1]={tostring(a6),Y,an}end;a9()a.log("AUTH: password changed for uid="..tostring(a6))return true end;function b.setUsername(a6,ao)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.currentProcess and a.currentProcess.euid or a.currentUID or 0;if am~=0 then return nil,"Permission denied (root only)"end;if type(ao)~="string"or#ao==0 then return nil,"Invalid username"end;if not ao:match("^[a-z_][a-z0-9_%-]*$")or#ao>32 then return nil,"Invalid username format"end;if ac(ao)then return nil,"Username already taken"end;local ag=aa(a6)if not ag then return nil,"No such user"end;local ap=ag[3]ag[3]=ao;a.users[a6]=ao;a7()a.log("AUTH: uid="..tostring(a6).." renamed '"..ap.."' → '"..ao.."'")return true end;function b.newUser(ad,X,aq,ar,as)local am=a.currentProcess and a.currentProcess.euid or a.currentUID or 0;if am~=0 then return nil,"Permission denied (root only)"end;if type(ad)~="string"or#ad==0 then return nil,"Invalid username"end;if not ad:match("^[a-z_][a-z0-9_%-]*$")or#ad>32 then return nil,"Invalid username format"end;if ac(ad)then return nil,"Username already exists"end;if type(X)~="string"or#X<6 then return nil,"Password is too short (minimum 6 characters)"end;local a6=ae()aq=tonumber(aq)or a6;ar=ar or"/home/"..ad;as=as or"/bin/hysh"a2[#a2+1]={tostring(a6),tostring(aq),ad,ar,as}a.users[a6]=ad;local Y=V()local an=W(X,Y)a3[#a3+1]={tostring(a6),Y,an}a7()a9()if a.vfs.mkdir and not a.vfs.exists(ar)then a.vfs.mkdir(ar)pcall(a.vfs.chown,ar,a6,a6)end;a.log("AUTH: new user '"..ad.."' uid="..tostring(a6))return a6 end;function b.whoami()local a6=a.currentProcess and a.currentProcess.euid or a.currentUID;if not a6 then return nil,"Not logged in"end;return a.users[a6]or"uid="..tostring(a6)end;function b.getUID(ad)local ag=ac(ad)if ag then return tonumber(ag[1])end;return nil end;function b.getPasswd(a6)a6=tonumber(a6)local ag=aa(a6)if not ag then return nil end;return{uid=tonumber(ag[1]),gid=tonumber(ag[2]),username=ag[3],homedir=ag[4],shell=ag[5]}end;function b.deleteUser(a6)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;if a6==0 then return nil,"Cannot delete root"end;local ag=aa(a6)if not ag then return nil,"No such user"end;local ad=ag[3]for n,D in ipairs(a2)do if tonumber(D[1])==a6 then table.remove(a2,n)break end end;for n,D in ipairs(a3)do if tonumber(D[1])==a6 then table.remove(a3,n)break end end;a.users[a6]=nil;a7()a9()a.log("AUTH: deleted user '"..ad.."' uid="..tostring(a6))return true end;function b.lockUser(a6)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;if a6==0 then return nil,"Cannot lock root"end;local ah=ab(a6)if not ah then return nil,"No shadow entry for uid"end;if ah[3]:sub(1,1)~="!"then ah[3]="!"..ah[3]end;a9()a.log("AUTH: locked uid="..tostring(a6))return true end;function b.unlockUser(a6)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;local ah=ab(a6)if not ah then return nil,"No shadow entry for uid"end;if ah[3]:sub(1,1)=="!"then ah[3]=ah[3]:sub(2)end;a9()a.log("AUTH: unlocked uid="..tostring(a6))return true end;function b.listUsers()local at={}for a4,D in ipairs(a2)do local a6=tonumber(D[1])local ah=ab(a6)local au=ah and ah[3]:sub(1,1)=="!"at[#at+1]={uid=a6,gid=tonumber(D[2]),username=D[3],homedir=D[4],shell=D[5],locked=au or false}end;return at end;function b.setShell(a6,as)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 and am~=a6 then return nil,"Permission denied"end;if type(as)~="string"or#as==0 then return nil,"Invalid shell"end;local ag=aa(a6)if not ag then return nil,"No such user"end;ag[5]=as;a7()a.log("AUTH: uid="..tostring(a6).." shell -> "..as)return true end;function b.setHomedir(a6,ar)a6=tonumber(a6)if not a6 then return nil,"Invalid uid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;if type(ar)~="string"or#ar==0 then return nil,"Invalid homedir"end;local ag=aa(a6)if not ag then return nil,"No such user"end;ag[4]=ar;a7()a.log("AUTH: uid="..tostring(a6).." homedir -> "..ar)return true end;function b.setGID(a6,aq)a6=tonumber(a6)aq=tonumber(aq)if not a6 or not aq then return nil,"Invalid uid or gid"end;local am=a.uid or 0;if am~=0 then return nil,"Permission denied (root only)"end;local ag=aa(a6)if not ag then return nil,"No such user"end;ag[2]=tostring(aq)a7()a.log("AUTH: uid="..tostring(a6).." gid -> "..tostring(aq))return true end;function b.elevate(av,X)if type(av)~="string"or type(X)~="string"then return nil,"Authentication failure"end;local ag=ac(av)if not ag then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local a6=tonumber(ag[1])local ah=ab(a6)if not ah then W(X,"aaaaaaaaaaaaaaaa")return nil,"Authentication failure"end;local aj=W(X,ah[2])if aj~=ah[3]then return nil,"Authentication failure"end;local aw=a.currentTask;local ax=aw.uid;aw.uid=0;aw.euid=0;aw.gid=0;aw.egid=0;a.uid=0;a.log("AUTH: elevate uid="..tostring(ax).." -> 0 (via "..av..")")return true,a6 end;if a.syscalls then a.syscalls["login"]=b.login;a.syscalls["setpassword"]=b.setPassword;a.syscalls["setusername"]=b.setUsername;a.syscalls["newuser"]=b.newUser;a.syscalls["whoami"]=b.whoami;a.syscalls["getuidbyname"]=b.getUID;a.syscalls["getpasswd"]=b.getPasswd;a.syscalls["elevate"]=b.elevate;a.syscalls["deleteuser"]=b.deleteUser;a.syscalls["lockuser"]=b.lockUser;a.syscalls["unlockuser"]=b.unlockUser;a.syscalls["listusers"]=b.listUsers;a.syscalls["setshell"]=b.setShell;a.syscalls["sethomedir"]=b.setHomedir;a.syscalls["setgid"]=b.setGID end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod new file mode 100644 index 0000000..852a690 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod @@ -0,0 +1 @@ +local a=...local b={}local c={}local d=2;a.exitMain=false;local e=coroutine.resumeWithTimeout;local function f(g,h)return math.floor(g/2^h)%2==1 end;local function i(j)a.vfs.access(j,"rx")local k=a.vfs.open(j,"r")local l=a.vfs.read(k,1024*1024*4)a.vfs.close(k)local m=a.freshUserEnv()local n,o=load(l,"@"..j,"t",m)if not n then error("ENOEXEC: "..tostring(o))end;local p=a.vfs.lstat(j)local q=f(p.perms,6)local r=a.currentTask and a.currentTask.uid or a.uid;local s=q and p.owner or r;return n,s,q end;local function t(n,u,v,w,x,y,z)local A=d;d=d+1;b[tostring(A)]={coro=coroutine.create(function()local B,o=xpcall(n,debug.traceback,table.unpack(w or{}))if a.config.logTaskExit then if not B then a.log("Task "..tostring(A).." exited with err: "..tostring(o),"ERROR",0xFF0000)elseif o then a.log("Task "..tostring(A).." exited with code: "..tostring(o),"DBUG",0x00FFFF)else a.log("Task "..tostring(A).." exited without code","DBUG",0x00FFFF)end end;if type(o)=="number"then b[tostring(A)].exit=o end;if b[tostring(A)].fd then for k,C in pairs(b[tostring(A)].fd)do pcall(a.vfs.close,k)end end;b[tostring(A)].status="Z"end),name=u or"task"..tostring(A),envars=v or(a.currentTask and a.currentTask.envars or{}),args=w or{},status="R",pid=A,tgid=x or(a.currentTask and a.currentTask.tgid or A),uid=y,euid=z,gid=a.currentTask and a.currentTask.gid or 0,groups=a.currentTask and a.currentTask.groups or{},fd={},sleep=0,ivs=0,vs=0,children={},parent=a.currentTask or a.kernelTask,siblings=a.currentTask and a.currentTask.children or a.kernelTask.children,syscallReturn={},cwd=a.currentTask and a.currentTask.cwd or"/",timeSlice=0,lastTime=0,totalTime=0,numRuns=0}table.insert(a.currentTask and a.currentTask.children or a.kernelTask.children,b[tostring(A)])return A end;function c.spawn(n,u,v,w,x)local D=a.currentTask;local y=D and D.uid or a.uid;local z=D and D.euid or y;return t(n,u,v,w,x,y,z)end;function c.execspawn(j,u,v,w,x)local n,s,E=i(j,a._U)local D=a.currentTask;local y=D and D.uid or a.uid;if E then a.log("execspawn: suid exec '"..j.."' caller_uid="..tostring(y).." -> euid="..tostring(s))end;return t(n,u or j,v,w,x,y,s)end;function c.exec(j,w,v)local F=a.currentTask;local n,s,C=i(j,a._U)if F.fd then for k,C in pairs(F.fd)do if k>2 then pcall(a.vfs.close,k)end end end;F.euid=s;F.args=w or{}F.envars=v or F.envars;F.name=j;F.coro=coroutine.create(function()local B,o=xpcall(n,debug.traceback,table.unpack(F.args))if a.config.logTaskExit then if not B then a.log("Task "..tostring(F.pid).." exec '"..j.."' err: "..tostring(o),"ERROR",0xFF0000)else a.log("Task "..tostring(F.pid).." exec '"..j.."' exited: "..tostring(o),"DBUG",0x00FFFF)end end;if type(o)=="number"then b[tostring(F.pid)].exit=o end;if b[tostring(F.pid)].fd then for k,C in pairs(b[tostring(F.pid)].fd)do pcall(a.vfs.close,k)end end;b[tostring(F.pid)].status="Z"end)F.syscallReturn={}coroutine.yield()end;function c.sleep(G)a.currentTask.status="S"a.currentTask.sleep=a.EFI:getEpochMs()+G*1000 end;function c.getTask(H)local F=b[tostring(H)]if not F then return nil end;local I,J={},{}for K,L in ipairs(F.children)do I[K]=L.pid end;for K,L in ipairs(F.siblings)do J[K]=L.pid end;return{name=F.name,status=F.status,pid=F.pid,tgid=F.tgid,username=a.users[F.uid],uid=F.uid,euid=F.euid,exit=F.exit,sleep=F.sleep,ivs=F.ivs,vs=F.vs,children=I,siblings=J,parent=F.parent.pid,cwd=F.cwd,term=F.term}end;function c.collect(H)local I={}for C,L in ipairs(a.currentTask.children)do I[#I+1]=L.pid end;local F=b[tostring(H)]if not F then return false,"Task does not exist"elseif not isEqualToAny(F.pid,table.unpack(I))then return false,"You do not own this task"elseif F.status~="Z"then return false,"Task must exit to collect status"else F.reapTime=0;return true,F.exit end end;function c.kill(H)local F=b[tostring(H)]if not F then return false,"Task does not exist"elseif F.status=="Z"then return false,"Task is already dead"end;local D=a.currentTask;local M=D and(D.euid or D.uid)or a.uid;if M~=0 and F.uid~=(D and D.uid or a.uid)then return false,"EPERM"end;F.status="Z"return true end;function c.stop(H)local F=b[tostring(H)]if not F then return false,"Task does not exist"elseif F.status~="R"then return false,"Cannot stop non-running task"else F.status="T"return true end end;function c.continue(H)local F=b[tostring(H)]if not F then return false,"Task does not exist"elseif F.status~="T"then return false,"Task is not stopped"else F.status="R"return true end end;function c.getpid()return a.currentTask.pid end;function c.getppid()return a.currentTask.parent.pid end;function c.getTasks()local N={}for C,L in pairs(b)do N[#N+1]=L.pid end;return N end;function c.getEnviron(O)return a.currentTask.envars[O]end;function c.setEnviron(O,P)a.currentTask.envars[O]=P end;function c.exit(Q)local F=a.currentTask;if a.config.logTaskExit then if Q then a.log("Task "..tostring(F.pid).." exited with code: "..tostring(Q),"DBUG",0x00FFFF)else a.log("Task "..tostring(F.pid).." exited without code","DBUG",0x00FFFF)end end;b[tostring(F.pid)].status="Z"if type(Q)=="number"then b[tostring(F.pid)].exit=Q end end;function c.setuid(R)local F=a.currentTask;if F.euid~=0 and F.uid~=R then error("EPERM")end;F.uid=R;F.euid=R;a.uid=R end;function c.geteuid()return a.currentTask.euid end;function c.getuid()return a.currentTask.uid end;local function S()for H,F in pairs(b)do if F.status=="Z"and not F.reapTime then F.coro=nil;F.ivs=nil;F.vs=nil;F.args=nil;F.envars=nil;F.cwd=nil;F.numRuns=nil;F.totalTime=nil;F.lastTime=nil;F.timeSlice=nil;F.syscallReturn=nil;F.sleep=nil;F.fd=nil;F.reapTime=a.EFI:getEpochMs()+30000 elseif F.reapTime and a.EFI:getEpochMs()>F.reapTime and F.status=="Z"then for C,T in ipairs(F.children)do T.parent=b["1"]T.siblings=b["1"].children;table.insert(b["1"].children,T)end;for K,U in ipairs(F.siblings)do if U.pid==F.pid then table.remove(F.siblings,K)break end end;b[H]=nil end end end;local V=0.85;local W=0.01;local X=0.0005;local Y=0.5;local Z=0.08;local _=0.03;local a0=0.02;local a1=0.5;local a2=0.5;local a3=0.01;function a.main()while not a.exitMain do local a4=0;local a5=0;local a6=0;local a7=0;local a8={}for H,F in pairs(b)do a.currentTask=F;a.uid=F.euid or F.uid;a.process=F.name;if F.status=="S"and a.EFI:getEpochMs()>=F.sleep then F.status="R"F.sleep=0 end;if F.status=="D"then if F.ksh then coroutine.resume(F.ksh)end end;if F.status=="R"then a4=a4+1;F.timeSlice=math.min(Y,math.max(X,a3/a4^V))if F.sigq and#F.sigq~=0 and F.sigh then local a9=coroutine.create(F.sigh)local aa,o=coroutine.resumeWithTimeout(a9,100,table.remove(F.sigq,1))if aa=="error"then F.sigd.error=o;F.sigd.active=false;F.sigh=nil;F.sigq=nil;F.sigd=nil elseif aa=="success"then if o=="syscall"then F.sigd.error="Cannot execute syscalls from signals"F.sigd.active=false;F.sigh=nil;F.sigq=nil;F.sigd=nil end end end;if F.status=="R"then local ab=a.EFI:getEpochMs()local N;if a.config.preempt then N={e(F.coro,F.timeSlice,table.unpack(F.syscallReturn))}else N={coroutine.resume(F.coro,table.unpack(F.syscallReturn))}end;local ac=a.EFI:getEpochMs()-ab;F.lastTime=ac;F.totalTime=(F.totalTime or 0)+ac;F.numRuns=(F.numRuns or 0)+1;a8[#a8+1]=ac;a7=a7+ac;if ac<=X then a5=a5+1 end;if ac>=Y then a6=a6+1 end;if N[1]=="error"or N[1]==false then a.log("processHandlerException: "..tostring(N[2]),"ERROR",0xFF0000)F.status="Z"F.exit="processHandlerException: "..tostring(N[2])elseif N[1]=="timeout"then F.ivs=F.ivs+1;F.syscallReturn={}elseif N[1]=="success"or N[1]==true then F.vs=F.vs+1;if N[2]=="syscall"then local ad=N[3]if a.syscalls[ad]then if a.config.debugSyscalls then a.log("Task "..F.pid.." syscall: "..ad,"DBUG",0x00FFFF)for K=4,#N do a.log(" inval["..K-3 .."] = "..tostring(N[K]),"DBUG",0x00FFFF)end end;local ae={xpcall(a.syscalls[ad],debug.traceback,table.unpack(N,4))}if a.config.debugSyscalls then if not ae[1]then a.log("Task "..F.pid.." syscall "..ad.." failed: "..tostring(ae[2]),"ERROR",0xFF0000)else a.log("Task "..F.pid.." syscall "..ad.." ok, "..#ae-1 .." retvals","DBUG",0x00FFFF)for K=2,#ae do local L=type(ae[K])=="table"and table.serialize(ae[K])or tostring(ae[K])a.log(" retval["..K-1 .."] = "..L,"DBUG",0x00FFFF)end end end;if not ae[1]then F.syscallReturn={false,ae[2]}else F.syscallReturn={true,table.unpack(ae,2)}end else F.syscallReturn={false,"Unknown syscall: "..tostring(ad)}end end end end end end;local af=a4>0 and a7/a4 or 0;local ag=0;for C,ah in ipairs(a8)do ag=ag+(ah-af)^2 end;if a4>0 then ag=ag/a4 end;if a4>0 then local ai=a1*a5/a4-a2*a6/a4;local aj=W*a4^(V-1)/math.max(af,1e-8)a3=a3+Z*(aj-a3)+_*ai-a0*ag end;S()end end;local ak=a.syscalls;ak["spawn"]=c.spawn;ak["execspawn"]=c.execspawn;ak["exec"]=c.exec;ak["sleep"]=c.sleep;ak["getTask"]=c.getTask;ak["collect"]=c.collect;ak["kill"]=c.kill;ak["stop"]=c.stop;ak["continue"]=c.continue;ak["getpid"]=c.getpid;ak["getppid"]=c.getppid;ak["getTasks"]=c.getTasks;ak["setEnviron"]=c.setEnviron;ak["getEnviron"]=c.getEnviron;ak["exit"]=c.exit;ak["setuid"]=c.setuid;ak["getuid"]=c.getuid;ak["geteuid"]=c.geteuid;a._G.sleep=function(...)coroutine.yield("syscall","sleep",...)end;a.tasks=b;a.hpv=c diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/47_dbg.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/47_dbg.kmod new file mode 100644 index 0000000..04dd7b9 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/47_dbg.kmod @@ -0,0 +1 @@ +local a=...local debug=debug;a._G.debug={getinfo=debug.getinfo,traceback=debug.traceback} diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/50_gpio.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/50_gpio.kmod new file mode 100644 index 0000000..43c6f13 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/50_gpio.kmod @@ -0,0 +1 @@ +local a=...local b=a.syscalls;a.gpio={}b["gpio_write"]=function(c,d)if a.gpio[c]then return a.gpio[c]("w",d)end end;b["gpio_writeAnalog"]=function(c,d)if a.gpio[c]then return a.gpio[c]("wa",d)end end;b["gpio_read"]=function(c)if a.gpio[c]then return a.gpio[c]("r")end end;b["gpio_readAnalog"]=function(c)if a.gpio[c]then return a.gpio[c]("ra")end end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/70_stdlibadv.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/70_stdlibadv.kmod new file mode 100644 index 0000000..b097403 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/70_stdlibadv.kmod @@ -0,0 +1 @@ +local a=...function print(...)local b={...}local c=""for d=1,#b do c=c..tostring(b[d]).."\t"end;c=c:sub(1,-2)syscall.write(1,c.."\n")end;function printf(e,...)local c=string.format(e,...)syscall.write(1,c.."\n")end;function printInline(...)local b={...}local c=""for d=1,#b do c=c..tostring(b[d]).."\t"end;c=c:sub(1,-2)syscall.write(1,c)end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/90_init.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/90_init.kmod new file mode 100644 index 0000000..a06234b --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/90_init.kmod @@ -0,0 +1 @@ +local a=...a.log("Loading init system...")a.log("InitPath: "..a.config.initPath)local b,c=pcall(a.vfs.access,a.config.initPath,"rx")if not b then a.PANIC("Init binary not executable: "..a.config.initPath.." ("..tostring(c)..")")end;local d=a.vfs.open(a.config.initPath,"r")if not d then a.panic("Failed to open "..a.config.initPath)end;local e=a.vfs.read(d,1024*1024*4)if not d then a.panic("Failed to read "..a.config.initPath)end;a.vfs.close(d)local f,g=load(e,"@sysinit","t",a._U)if not f then a.PANIC("Failed to load init system: "..g)end;a.tasks["1"]={coro=coroutine.create(function()local h,g=xpcall(f,debug.traceback,a)if not h then a.panic("Init system crashed: "..tostring(g))else a.panic("Init system exited: "..tostring(g))end end),name="sysinit",status="R",pid=1,tgid=1,uid=0,fd={},envars={},args={},exit="",sleep=0,ivs=0,vs=0,parent=a.kernelTask,siblings=a.kernelTask.children,children={},syscallReturn={},cwd="/",timeSlice=0,lastTime=0,totalTime=0,numRuns=0}a.log("created init task with PID 1")a.log("Initializing init system...") diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/91_login.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/91_login.kmod new file mode 100644 index 0000000..5a3b526 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/91_login.kmod @@ -0,0 +1 @@ +local a=...if not a.vfs.exists("/root")then a.vfs.mkdir("/root")end;a.processes.login=function()local b,c=pcall(a.hpv.execspawn,"/bin/login","login")if not b then a.log("Failed to exec /bin/login: "..tostring(c),"ERROR",0xFF0000)end end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/92_setup.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/92_setup.kmod new file mode 100644 index 0000000..64f25bf --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/92_setup.kmod @@ -0,0 +1 @@ +local a=...if a.firstBoot then local b=a.vfs.P;local c=a.vfs.PERM;local d=b.OWNER_R+b.OWNER_W+b.GROUP_R+b.WORLD_R;local e=b.OWNER_R+b.OWNER_W+b.OWNER_X+b.GROUP_R+b.GROUP_X+b.WORLD_R+b.WORLD_X;local f=b.OWNER_R+b.OWNER_W+b.GROUP_R;local g=b.OWNER_R+b.OWNER_W;local h=c.RWXRWXRWX;local i=c.SUID_755;local j=0x02;local k=a.disks["$"]local function l(m,n,o,p,q,r)r=r or""local s=q%256;local t=math.floor(q/256)%256;local u=(o or 0)%256;local v=math.floor((o or 0)/256)%256;local w=(p or 0)%256;local x=math.floor((p or 0)/256)%256;return string.char(#m)..m..string.char(n,u,v,w,x,s,t)..string.char(#r)..r end;local y=0x00;local function z(A,B)local C=A;if C:sub(1,1)=="/"then C=C:sub(2)end;local D=C==""and".meta"or C.."/.meta"local E={}local F,G=pcall(function()return k:open(D,"r")end)if F and G then local H=G.read(65535)if G.close then G.close()end;E=a.vfs._parseMetafile and a.vfs._parseMetafile(H)or{}end;for I,J in ipairs(B)do local m=J[1]local n=J[2]or y;local o=J[3]or 0;local p=J[4]or 0;local q=J[5]or e;local r=J[6]or""E[m]={etype=n,owner=o,group=p,perms=q,cmeta=r}end;local K=string.char(j)for m,L in pairs(E)do K=K..l(m,L.etype or y,L.owner or 0,L.group or 0,L.perms or e,L.cmeta or"")end;local M,N=pcall(function()local O=k:open(D,"w")O.write(K)O.close()end)if not M then a.log("permissions: failed to write "..D..": "..tostring(N),"WARN",0xFF8800)end end;a.log("Seeding filesystem permissions...")z("/",{{"bin",y,0,0,e},{"boot",y,0,0,e},{"dev",y,0,0,h},{"etc",y,0,0,e},{"home",y,0,0,e},{"lib",y,0,0,e},{"proc",y,0,0,h},{"root",y,0,0,g},{"sbin",y,0,0,e},{"tmp",y,0,0,h},{"usr",y,0,0,e},{"var",y,0,0,h},{"opt",y,0,0,e}})z("/bin",{{"login",y,0,0,i},{"su",y,0,0,i},{"sudo",y,0,0,i}})z("/etc",{{"passwd",y,0,0,d},{"shadow",y,0,0,g},{"pam.d",y,0,0,g}})z("/etc/pam.d",{{"secret",y,0,0,g}})a.log("Filesystem permissions seeded.")end diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/99_final.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/99_final.kmod new file mode 100644 index 0000000..b05feb5 --- /dev/null +++ b/prod/Hyperion-kernel/lib/modules/hyperion/99_final.kmod @@ -0,0 +1 @@ +local a=...a.allowGlobalOverwrites=false diff --git a/prod/bit32/lib/bit32 b/prod/bit32/lib/bit32 new file mode 100644 index 0000000..174055a --- /dev/null +++ b/prod/bit32/lib/bit32 @@ -0,0 +1 @@ +local a={}local b=2^32;local c=2^31;local function d(e)return e%b end;local function f(e)e=d(e)local g={}for h=0,31 do local i=e%2;g[h]=i;e=(e-i)/2 end;return g end;local function j(g)local e=0;local k=1;for h=0,31 do if g[h]==1 then e=e+k end;k=k*2 end;return d(e)end;function a.band(...)local l={...}if#l==0 then return 0xFFFFFFFF end;local m=f(l[1])for h=2,#l do local i=f(l[h])for n=0,31 do m[n]=m[n]==1 and i[n]==1 and 1 or 0 end end;return j(m)end;function a.bor(...)local l={...}if#l==0 then return 0 end;local m=f(l[1])for h=2,#l do local i=f(l[h])for n=0,31 do m[n]=(m[n]==1 or i[n]==1)and 1 or 0 end end;return j(m)end;function a.bxor(...)local l={...}if#l==0 then return 0 end;local m=f(l[1])for h=2,#l do local i=f(l[h])for n=0,31 do m[n]=m[n]~=i[n]and 1 or 0 end end;return j(m)end;function a.bnot(e)local m=f(e)for h=0,31 do m[h]=m[h]==1 and 0 or 1 end;return j(m)end;function a.lshift(e,o)return d(d(e)*2^o)end;function a.rshift(e,o)return math.floor(d(e)/2^o)end;function a.arshift(e,o)e=d(e)if e>=c then return math.floor((e-b)/2^o)else return math.floor(e/2^o)end end;function a.lrotate(e,o)o=o%32;e=d(e)local p=e*2^o%b;local q=math.floor(e/2^(32-o))return d(p+q)end;function a.rrotate(e,o)o=o%32;e=d(e)local q=math.floor(e/2^o)local p=e*2^(32-o)%b;return d(p+q)end;function a.extract(e,r,s)s=s or 1;return a.band(a.rshift(e,r),2^s-1)end;function a.replace(e,t,r,s)s=s or 1;local u=a.lshift(2^s-1,r)e=a.band(e,a.bnot(u))return a.bor(e,a.lshift(t,r))end;return a diff --git a/prod/blake2s/lib/crypto/blake2s b/prod/blake2s/lib/crypto/blake2s new file mode 100644 index 0000000..0a4e761 --- /dev/null +++ b/prod/blake2s/lib/crypto/blake2s @@ -0,0 +1 @@ +local a=require("bit32")local b,c,d=a.band,a.bor,a.bxor;local e,f=a.rshift,a.lshift;local g=2^32;local function h(i,j)return c(e(i,j),f(i,32-j))end;local k={0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19}local l={{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 m(n,o,p,q,r,i,s)n[o]=(n[o]+n[p]+i)%g;n[r]=h(d(n[r],n[o]),16)n[q]=(n[q]+n[r])%g;n[p]=h(d(n[p],n[q]),12)n[o]=(n[o]+n[p]+s)%g;n[r]=h(d(n[r],n[o]),8)n[q]=(n[q]+n[r])%g;n[p]=h(d(n[p],n[q]),7)end;local function t(u,v,w,x)local n={}for y=1,8 do n[y]=u[y]end;for y=1,8 do n[y+8]=k[y]end;n[13]=d(n[13],w)if x then n[15]=d(n[15],0xFFFFFFFF)end;local z={}for y=0,15 do local A=y*4+1;z[y]=(v:byte(A)or 0)+(v:byte(A+1)or 0)*0x100+(v:byte(A+2)or 0)*0x10000+(v:byte(A+3)or 0)*0x1000000 end;for B=1,10 do local C=l[B]m(n,1,5,9,13,z[C[1]],z[C[2]])m(n,2,6,10,14,z[C[3]],z[C[4]])m(n,3,7,11,15,z[C[5]],z[C[6]])m(n,4,8,12,16,z[C[7]],z[C[8]])m(n,1,6,11,16,z[C[9]],z[C[10]])m(n,2,7,12,13,z[C[11]],z[C[12]])m(n,3,8,9,14,z[C[13]],z[C[14]])m(n,4,5,10,15,z[C[15]],z[C[16]])end;for y=1,8 do u[y]=d(u[y],n[y],n[y+8])end end;local function D(E,F)F=F or""local u={}for y=1,8 do u[y]=k[y]end;local G=32;u[1]=d(u[1],0x01010000+f(#F,8)+G)local w=0;if#F>0 then local v=F..string.rep("\0",64-#F)w=#F;t(u,v,w,false)end;for y=1,#E,64 do local v=E:sub(y,y+63)if#v<64 then v=v..string.rep("\0",64-#v)end;w=w+math.min(64,#E-y+1)t(u,v,w,y+64>#E)end;local H=""for y=1,8 do H=H..string.format("%08x",u[y])end;return H end;return D diff --git a/prod/deflate/lib/LibDeflate b/prod/deflate/lib/LibDeflate new file mode 100644 index 0000000..6b2a6ae --- /dev/null +++ b/prod/deflate/lib/LibDeflate @@ -0,0 +1 @@ +local a;do local b="1.0.0-release"local c="LibDeflate "..b.." Copyright (C) 2018 Haoqian He.".." License GPLv3+: GNU GPL version 3 or later"if LibStub then local d,e="LibDeflate",-1;local f,g=LibStub:GetLibrary(d,true)if f and g and g>=e then return f else a=LibStub:NewLibrary(d,b)end else a={}end;a._VERSION=b;a._COPYRIGHT=c end;local assert=assert;local error=error;local pairs=pairs;local h=string.byte;local i=string.char;local j=string.find;local k=string.gsub;local l=string.sub;local m=table.concat;local n=table.sort;local tostring=tostring;local type=type;local o={}local p={}local q={}local r={}local s={}local t={}local u={}local v={}local w={}local x={3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}local y={0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}local z={[0]=1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}local A={[0]=0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}local B={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}local C;local D;local E;local F;local G;local H;local I;local J;for K=0,255 do p[K]=i(K)end;do local L=1;for K=0,32 do o[K]=L;L=L*2 end end;for K=1,9 do q[K]={}for M=0,o[K+1]-1 do local N=0;local O=M;for P=1,K do N=N-N%2+((N%2==1 or O%2==1)and 1 or 0)O=(O-O%2)/2;N=N*2 end;q[K][M]=(N-N%2)/2 end end;do local Q=18;local R=16;local S=265;local T=1;for U=3,258 do if U<=10 then r[U]=U+254;t[U]=0 elseif U==258 then r[U]=285;t[U]=0 else if U>Q then Q=Q+R;R=R*2;S=S+4;T=T+1 end;local V=U-Q-1+R/2;r[U]=(V-V%(R/8))/(R/8)+S;t[U]=T;s[U]=V%(R/8)end end end;do u[1]=0;u[2]=1;w[1]=0;w[2]=0;local Q=3;local R=4;local W=2;local T=0;for X=3,256 do if X>R then Q=Q*2;R=R*2;W=W+2;T=T+1 end;u[X]=X<=Q and W or W+1;w[X]=T<0 and 0 or T;if R>=8 then v[X]=(X-R/2-1)%(R/4)end end end;local Y,Z,_,a0,a1;if bit~=nil then Y=bit.band;Z=bit.bnot;_=bit.bxor;a0=bit.blshift;a1=bit.blogic_rshift elseif bit32~=nil then Y=bit32.band;Z=bit32.bnot;_=bit32.bxor;a0=bit32.lshift;a1=bit32.rshift else _=function(Q,R)local a2=0;for K=32,0,-1 do local a3=2^K;local a4=false;local a5=false;if Q==0 then a2=a2+R;break end;if R==0 then a2=a2+Q;break end;if Q>=a3 then a4=true;Q=Q-a3 end;if R>=a3 then a5=true;R=R-a3 end;if not(a4 and a5)and(a4 or a5)then a2=a2+a3 end end;return a2 end;a0=function(a6,a7)local a8=a6*2^a7;return a8%2^32 end;a1=function(a6,a9)local a8=a6/2^a9;return math.floor(a8)end;Y=function(Q,R)local aa,S=1,0;while Q>0 and R>0 do local ab,ac=Q%2,R%2;if ab+ac>1 then S=S+aa end;Q,R,aa=(Q-ab)/2,(R-ac)/2,aa*2 end;return S end;Z=function(ad)return bxor(ad,2^(bits or floor(log(ad,2)))-1)end end;local ae=0xEDB88320;local function af(ag)local ah={}local V=setmetatable({},ah)function ah:__index(ai)local aj=ag(ai)V[ai]=aj;return aj end;return V end;local ak=af(function(K)local al=K;for P=1,8 do local R=Y(al,1)al=a1(al,1)if R==1 then al=_(al,ae)end end;return al end)local function am(an,al)al=Z(al or 0)local ao=a1(al,8)local ap=ak[_(al%256,an)]return Z(_(ao,ap))end;local function aq(ar,al)al=al or 0;for K=1,#ar do al=am(ar:byte(K),al)end;return al end;function a:CRC32(ar,al)if type(ar)=='string'then return aq(ar,al)else return am(ar,al)end end;function a:Adler32(as)if type(as)~="string"then error(("Usage: LibDeflate:Adler32(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;local at=#as;local K=1;local Q=1;local R=0;while K<=at-15 do local au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aI,aJ=h(as,K,K+15)R=(R+16*Q+16*au+15*av+14*aw+13*ax+12*ay+11*az+10*aA+9*aB+8*aC+7*aD+6*aE+5*aF+4*aG+3*aH+2*aI+aJ)%65521;Q=(Q+au+av+aw+ax+ay+az+aA+aB+aC+aD+aE+aF+aG+aH+aI+aJ)%65521;K=K+16 end;while K<=at do local ad=h(as,K,K)Q=(Q+ad)%65521;R=(R+Q)%65521;K=K+1 end;return(R*65536+Q)%4294967296 end;local function aK(aL,aM)return aL%4294967296==aM%4294967296 end;function a:CreateDictionary(as,at,aN)if type(as)~="string"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'str' - string expected got '%s'."):format(type(as)),2)end;if type(at)~="number"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'strlen' - number expected got '%s'."):format(type(at)),2)end;if type(aN)~="number"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'adler32' - number expected got '%s'."):format(type(aN)),2)end;if at~=#as then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'strlen' does not match the actual length of 'str'.".." 'strlen': %u, '#str': %u .".." Please check if 'str' is modified unintentionally."):format(at,#as))end;if at==0 then error("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'str' - Empty string is not allowed.",2)end;if at>32768 then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'str' - string longer than 32768 bytes is not allowed.".." Got %d bytes."):format(at),2)end;local aO=self:Adler32(as)if not aK(aN,aO)then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." 'adler32' does not match the actual adler32 of 'str'.".." 'adler32': %u, 'Adler32(str)': %u .".." Please check if 'str' is modified unintentionally."):format(aN,aO))end;local aP={}aP.adler32=aN;aP.hash_tables={}aP.string_table={}aP.strlen=at;local aQ=aP.string_table;local aR=aP.hash_tables;aQ[1]=h(as,1,1)aQ[2]=h(as,2,2)if at>=3 then local K=1;local aS=aQ[1]*256+aQ[2]while K<=at-2-3 do local au,av,aw,ax=h(as,K+2,K+5)aQ[K+2]=au;aQ[K+3]=av;aQ[K+4]=aw;aQ[K+5]=ax;aS=(aS*256+au)%16777216;local V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=K-at;K=K+1;aS=(aS*256+av)%16777216;V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=K-at;K=K+1;aS=(aS*256+aw)%16777216;V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=K-at;K=K+1;aS=(aS*256+ax)%16777216;V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=K-at;K=K+1 end;while K<=at-2 do local ad=h(as,K+2)aQ[K+2]=ad;aS=(aS*256+ad)%16777216;local V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=K-at;K=K+1 end end;return aP end;local function aT(aP)if type(aP)~="table"then return false,("'dictionary' - table expected got '%s'."):format(type(aP))end;if type(aP.adler32)~="number"or type(aP.string_table)~="table"or type(aP.strlen)~="number"or aP.strlen<=0 or aP.strlen>32768 or aP.strlen~=#aP.string_table or type(aP.hash_tables)~="table"then return false,("'dictionary' - corrupted dictionary."):format(type(aP))end;return true,""end;local aU={[0]={false,nil,0,0,0},[1]={false,nil,4,8,4},[2]={false,nil,5,18,8},[3]={false,nil,6,32,32},[4]={true,4,4,16,16},[5]={true,8,16,32,32},[6]={true,8,16,128,128},[7]={true,8,32,128,256},[8]={true,32,128,258,1024},[9]={true,32,258,258,4096}}local function aV(as,aW,aP,aX,aY)if type(as)~="string"then return false,("'str' - string expected got '%s'."):format(type(as))end;if aW then local aZ,a_=aT(aP)if not aZ then return false,a_ end end;if aX then local b0=type(aY)if b0~="nil"and b0~="table"then return false,("'configs' - nil or table expected got '%s'."):format(type(aY))end;if b0=="table"then for ai,aj in pairs(aY)do if ai~="level"and ai~="strategy"then return false,("'configs' - unsupported table key in the configs: '%s'."):format(ai)elseif ai=="level"and not aU[aj]then return false,("'configs' - unsupported 'level': %s."):format(tostring(aj))elseif ai=="strategy"and aj~="fixed"and aj~="huffman_only"and aj~="dynamic"then return false,("'configs' - unsupported 'strategy': '%s'."):format(tostring(aj))end end end end;return true,""end;local b1=0;local b2=1;local b3=2;local b4=3;local function b5()local b6=0;local b7=0;local b8=0;local b9=0;local ba={}local bb={}local function bc(O,T)b7=b7+O*o[b8]b8=b8+T;b9=b9+T;if b8>=32 then b6=b6+1;ba[b6]=p[b7%256]..p[(b7-b7%256)/256%256]..p[(b7-b7%65536)/65536%256]..p[(b7-b7%16777216)/16777216%256]local bd=o[32-b8+T]b7=(O-O%bd)/bd;b8=b8-32 end end;local function be(as)for P=1,b8,8 do b6=b6+1;ba[b6]=i(b7%256)b7=(b7-b7%256)/256 end;b8=0;b6=b6+1;ba[b6]=as;b9=b9+#as*8 end;local function bf(bg)if bg==b4 then return b9 end;if bg==b2 or bg==b3 then local bh=(8-b8%8)%8;if b8>0 then b7=b7-o[b8]+o[b8+bh]for P=1,b8,8 do b6=b6+1;ba[b6]=p[b7%256]b7=(b7-b7%256)/256 end;b7=0;b8=0 end;if bg==b3 then b9=b9+bh;return b9 end end;local bi=m(ba)ba={}b6=0;bb[#bb+1]=bi;if bg==b1 then return b9 else return b9,m(bb)end end;return bc,be,bf end;local function bj(bk,bl,bm)bm=bm+1;bk[bm]=bl;local O=bl[1]local bn=bm;local bo=(bn-bn%2)/2;while bo>=1 and bk[bo][1]>O do local V=bk[bo]bk[bo]=bl;bk[bn]=V;bn=bo;bo=(bo-bo%2)/2 end end;local function bp(bk,bm)local bq=bk[1]local bl=bk[bm]local O=bl[1]bk[1]=bl;bk[bm]=bq;bm=bm-1;local bn=1;local br=bn*2;local bs=br+1;while br<=bm do local bt=bk[br]if bs<=bm and bk[bs][1]1 do local bM=bp(bk,bm)bm=bm-1;local bN=bp(bk,bm)bm=bm-1;local bO={bM[1]+bN[1],-1,bM,bN}bj(bk,bO,bm)bm=bm+1 end;local bP=0;local bQ={bk[1],0,0,0}local bR=1;local bS=1;bk[1][1]=0;while bS<=bR do local bl=bQ[bS]local T=bl[1]local bD=bl[2]local bt=bl[3]local bu=bl[4]if bt then bR=bR+1;bQ[bR]=bt;bt[1]=T+1 end;if bu then bR=bR+1;bQ[bR]=bu;bu[1]=T+1 end;bS=bS+1;if T>bz then bP=bP+1;T=bz end;if bD>=0 then bx[bD]=T;bH=bD>bH and bD or bH;bw[T]=(bw[T]or 0)+1 end end;if bP>0 then repeat local T=bz-1;while(bw[T]or 0)==0 do T=T-1 end;bw[T]=bw[T]-1;bw[T+1]=(bw[T+1]or 0)+2;bw[bz]=bw[bz]-1;bP=bP-2 until bP<=0;bS=1;for T=bz,1,-1 do local bT=bw[T]or 0;while bT>0 do local bD=bI[bS][2]bx[bD]=T;bT=bT-1;bS=bS+1 end end end;bJ=bv(bw,bx,by,bz)return bx,bJ,bH end end;local function bU(bV,bW,bX,bY)local bZ=0;local b_={}local c0={}local c1=0;local c2={}local c3=nil;local bL=0;bY=bY<0 and 0 or bY;local c4=bW+bY+1;for W=0,c4+1 do local U=W<=bW and(bV[W]or 0)or(W<=c4 and(bX[W-bW-1]or 0)or nil)if U==c3 then bL=bL+1;if U~=0 and bL==6 then bZ=bZ+1;b_[bZ]=16;c1=c1+1;c2[c1]=3;c0[16]=(c0[16]or 0)+1;bL=0 elseif U==0 and bL==138 then bZ=bZ+1;b_[bZ]=18;c1=c1+1;c2[c1]=127;c0[18]=(c0[18]or 0)+1;bL=0 end else if bL==1 then bZ=bZ+1;b_[bZ]=c3;c0[c3]=(c0[c3]or 0)+1 elseif bL==2 then bZ=bZ+1;b_[bZ]=c3;bZ=bZ+1;b_[bZ]=c3;c0[c3]=(c0[c3]or 0)+2 elseif bL>=3 then bZ=bZ+1;local c5=c3~=0 and 16 or(bL<=10 and 17 or 18)b_[bZ]=c5;c0[c5]=(c0[c5]or 0)+1;c1=c1+1;c2[c1]=bL<=10 and bL-3 or bL-11 end;c3=U;if U and U~=0 then bZ=bZ+1;b_[bZ]=U;c0[U]=(c0[U]or 0)+1;bL=0 else bL=1 end end end;return b_,c2,c0 end;local function c6(as,V,c7,c8,c9)local K=c7-c9;while K<=c8-15-c9 do V[K],V[K+1],V[K+2],V[K+3],V[K+4],V[K+5],V[K+6],V[K+7],V[K+8],V[K+9],V[K+10],V[K+11],V[K+12],V[K+13],V[K+14],V[K+15]=h(as,K+c9,K+15+c9)K=K+16 end;while K<=c8-c9 do V[K]=h(as,K+c9,K+c9)K=K+1 end;return V end;local function ca(cb,aQ,aR,cc,cd,c9,aP)local ce=aU[cb]local cf,cg,ch,ci,cj=ce[1],ce[2],ce[3],ce[4],ce[5]local ck=not cf and ch or 2147483646;local cl=cj-cj%4/4;local aS;local cm;local cn;local co=0;if aP then cm=aP.hash_tables;cn=aP.string_table;co=aP.strlen;assert(cc==1)if cd>=cc and co>=2 then aS=cn[co-1]*65536+cn[co]*256+aQ[1]local V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=-1 end;if cd>=cc+1 and co>=1 then aS=cn[co]*65536+aQ[1]*256+aQ[2]local V=aR[aS]if not V then V={}aR[aS]=V end;V[#V+1]=0 end end;aS=(aQ[cc-c9]or 0)*256+(aQ[cc+1-c9]or 0)local cp={}local cq=0;local cr={}local cs={}local ct=0;local cu={}local cv={}local cw=0;local cx={}local cy=0;local cz=false;local cA;local cB;local cC=0;local cD=0;local bS=cc;local cE=cd+(cf and 1 or 0)while bS<=cE do local cF=bS-c9;cA=cC;cB=cD;cC=0;aS=(aS*256+(aQ[cF+2]or 0))%16777216;local cG;local cH;local cI=aR[aS]local cJ;if not cI then cJ=0;cI={}aR[aS]=cI;if cm then cH=cm[aS]cG=cH and#cH or 0 else cG=0 end else cJ=#cI;cH=cI;cG=cJ end;if bS<=cd then cI[cJ+1]=bS end;if cG>0 and bS+2<=cd and(not cf or cA=cg and cl or cj;while cG>=1 and cK>0 do local c3=cH[cG]if bS-c3>32768 then break end;if c3=-257 then local cL=c3-c9;while M<258 and bS+M<=cd do if aQ[cL+M]==aQ[cF+M]then M=M+1 else break end end else local cL=co+c3;while M<258 and bS+M<=cd do if cn[cL+M]==aQ[cF+M]then M=M+1 else break end end end;if M>cC then cC=M;cD=bS-c3 end;if cC>=ci then break end end;cG=cG-1;cK=cK-1;if cG==0 and c3>0 and cm then cH=cm[aS]cG=cH and#cH or 0 end end end;if not cf then cA,cB=cC,cD end;if(not cf or cz)and(cA>3 or cA==3 and cB<4096)and cC<=cA then local W=r[cA]local cM=t[cA]local cN,cO,cP;if cB<=256 then cN=u[cB]cP=v[cB]cO=w[cB]else cN=16;cO=7;local Q=384;local R=512;while true do if cB<=Q then cP=(cB-R/2-1)%(R/4)break elseif cB<=R then cP=(cB-R/2-1)%(R/4)cN=cN+1;break else cN=cN+2;cO=cO+1;Q=Q*2;R=R*2 end end end;cq=cq+1;cp[cq]=W;cr[W]=(cr[W]or 0)+1;ct=ct+1;cs[ct]=cN;cu[cN]=(cu[cN]or 0)+1;if cM>0 then local cQ=s[cA]cw=cw+1;cv[cw]=cQ end;if cO>0 then cy=cy+1;cx[cy]=cP end;for K=bS+1,bS+cA-(cf and 2 or 1)do aS=(aS*256+(aQ[K-c9+2]or 0))%16777216;if cA<=ck then cI=aR[aS]if not cI then cI={}aR[aS]=cI end;cI[#cI+1]=K end end;bS=bS+cA-(cf and 1 or 0)cz=false elseif not cf or cz then local W=aQ[cf and cF-1 or cF]cq=cq+1;cp[cq]=W;cr[W]=(cr[W]or 0)+1;bS=bS+1 else cz=true;bS=bS+1 end end;cq=cq+1;cp[cq]=256;cr[256]=(cr[256]or 0)+1;return cp,cv,cr,cs,cx,cu end;local function cR(cr,cu)local cS,cT,bW=bF(cr,15,285)local cU,cV,bY=bF(cu,15,29)local cW,c2,cX=bU(cS,bW,cU,bY)local cY,cZ=bF(cX,7,18)local c_=0;for K=1,19 do local bD=B[K]local d0=cY[bD]or 0;if d0~=0 then c_=K end end;c_=c_-4;local d1=bW+1-257;local d2=bY+1-1;if d2<0 then d2=0 end;return d1,d2,c_,cY,cZ,cW,c2,cS,cT,cU,cV end;local function d3(cp,cs,c_,cY,cW,cS,cU)local d4=17;d4=d4+(c_+4)*3;for K=1,#cW do local W=cW[K]d4=d4+cY[W]if W>=16 then d4=d4+(W==16 and 2 or(W==17 and 3 or 7))end end;local d5=0;for K=1,#cp do local W=cp[K]local d6=cS[W]d4=d4+d6;if W>256 then d5=d5+1;if W>264 and W<285 then local d7=y[W-256]d4=d4+d7 end;local cN=cs[d5]local d8=cU[cN]d4=d4+d8;if cN>3 then local cO=(cN-cN%2)/2-1;d4=d4+cO end end end;return d4 end;local function d9(bc,da,cp,cv,cs,cx,d1,d2,c_,cY,cZ,cW,c2,cS,cT,cU,cV)bc(da and 1 or 0,1)bc(2,2)bc(d1,5)bc(d2,5)bc(c_,4)for K=1,c_+4 do local bD=B[K]local d0=cY[bD]or 0;bc(d0,3)end;local db=1;for K=1,#cW do local W=cW[K]bc(cZ[W],cY[W])if W>=16 then local dc=c2[db]bc(dc,W==16 and 2 or(W==17 and 3 or 7))db=db+1 end end;local d5=0;local dd=0;local de=0;for K=1,#cp do local df=cp[K]local bA=cT[df]local d6=cS[df]bc(bA,d6)if df>256 then d5=d5+1;if df>264 and df<285 then dd=dd+1;local dg=cv[dd]local d7=y[df-256]bc(dg,d7)end;local dh=cs[d5]local di=cV[dh]local d8=cU[dh]bc(di,d8)if dh>3 then de=de+1;local cP=cx[de]local cO=(dh-dh%2)/2-1;bc(cP,cO)end end end end;local function dj(cp,cs)local d4=3;local d5=0;for K=1,#cp do local W=cp[K]local d6=E[W]d4=d4+d6;if W>256 then d5=d5+1;if W>264 and W<285 then local d7=y[W-256]d4=d4+d7 end;local cN=cs[d5]d4=d4+5;if cN>3 then local cO=(cN-cN%2)/2-1;d4=d4+cO end end end;return d4 end;local function dk(bc,da,cp,cv,cs,cx)bc(da and 1 or 0,1)bc(1,2)local d5=0;local dd=0;local de=0;for K=1,#cp do local dl=cp[K]local bA=C[dl]local d6=E[dl]bc(bA,d6)if dl>256 then d5=d5+1;if dl>264 and dl<285 then dd=dd+1;local dg=cv[dd]local d7=y[dl-256]bc(dg,d7)end;local cN=cs[d5]local di=G[cN]bc(di,5)if cN>3 then de=de+1;local cP=cx[de]local cO=(cN-cN%2)/2-1;bc(cP,cO)end end end end;local function dm(cc,cd,b9)assert(cd-cc+1<=65535)local d4=3;b9=b9+3;local bh=(8-b9%8)%8;d4=d4+bh;d4=d4+32;d4=d4+(cd-cc+1)*8;return d4 end;local function dn(bc,be,da,as,cc,cd,b9)assert(cd-cc+1<=65535)bc(da and 1 or 0,1)bc(0,2)b9=b9+3;local bh=(8-b9%8)%8;if bh>0 then bc(o[bh]-1,bh)end;local dp=cd-cc+1;bc(dp,16)local dq=255-dp%256+(255-(dp-dp%256)/256)*256;bc(dq,16)be(as:sub(cc,cd))end;local function dr(aY,bc,be,bf,as,aP)local aQ={}local aR={}local da=nil;local cc;local cd;local ds;local b9=bf(b4)local at=#as;local c9;local cb;local dt;if aY then if aY.level then cb=aY.level end;if aY.strategy then dt=aY.strategy end end;if not cb then if at<2048 then cb=7 elseif at>65536 then cb=3 else cb=5 end end;while not da do if not cc then cc=1;cd=64*1024-1;c9=0 else cc=cd+1;cd=cd+32*1024;c9=cc-32*1024-1 end;if cd>=at then cd=at;da=true else da=false end;local cp,cv,cr,cs,cx,cu;local d1,d2,c_,cY,cZ,cW,c2,cS,cT,cU,cV;local du;local dv;local dw;if cb~=0 then c6(as,aQ,cc,cd+3,c9)if cc==1 and aP then local cn=aP.string_table;local dx=aP.strlen;for K=0,-dx+1<-257 and-257 or-dx+1,-1 do aQ[K]=cn[dx+K]end end;if dt=="huffman_only"then cp={}c6(as,cp,cc,cd,cc-1)cv={}cr={}cp[cd-cc+2]=256;for K=1,cd-cc+2 do local W=cp[K]cr[W]=(cr[W]or 0)+1 end;cs={}cx={}cu={}else cp,cv,cr,cs,cx,cu=ca(cb,aQ,aR,cc,cd,c9,aP)end;d1,d2,c_,cY,cZ,cW,c2,cS,cT,cU,cV=cR(cr,cu)du=d3(cp,cs,c_,cY,cW,cS,cU)dv=dj(cp,cs)end;dw=dm(cc,cd,b9)local dy=dw;dy=dv and dv0 and cd+1-V[1]>32768 then if dz==1 then else local dA={}local dB=0;for K=2,dz do M=V[K]if cd+1-M<=32768 then dB=dB+1;dA[dB]=M end end;aR[ai]=dA end end end end end end;local function dC(as,aP,aY)local bc,be,bf=b5()dr(aY,bc,be,bf,as,aP)local b9,dD=bf(b2)local bh=(8-b9%8)%8;return dD,bh end;local function dE(as,aP,aY)local bc,be,bf=b5()local dF=8;local dG=7;local dH=dG*16+dF;bc(dH,8)local dI=aP and 1 or 0;local dJ=2;local dK=dJ*64+dI*32;local dL=31-(dH*256+dK)%31;dK=dK+dL;bc(dK,8)if dI==1 then local aN=aP.adler32;local dM=aN%256;aN=(aN-dM)/256;local dN=aN%256;aN=(aN-dN)/256;local dO=aN%256;aN=(aN-dO)/256;local dP=aN%256;bc(dP,8)bc(dO,8)bc(dN,8)bc(dM,8)end;dr(aY,bc,be,bf,as,aP)bf(b3)local aN=a:Adler32(as)local dP=aN%256;aN=(aN-dP)/256;local dO=aN%256;aN=(aN-dO)/256;local dN=aN%256;aN=(aN-dN)/256;local dM=aN%256;bc(dM,8)bc(dN,8)bc(dO,8)bc(dP,8)local b9,dD=bf(b2)local bh=(8-b9%8)%8;return dD,bh end;function a:CompressDeflate(as,aY)local dQ,dR=aV(as,false,nil,true,aY)if not dQ then error("Usage: LibDeflate:CompressDeflate(str, configs): "..dR,2)end;return dC(as,nil,aY)end;function a:CompressDeflateWithDict(as,aP,aY)local dQ,dR=aV(as,true,aP,true,aY)if not dQ then error("Usage: LibDeflate:CompressDeflateWithDict".."(str, dictionary, configs): "..dR,2)end;return dC(as,aP,aY)end;function a:CompressZlib(as,aY)local dQ,dR=aV(as,false,nil,true,aY)if not dQ then error("Usage: LibDeflate:CompressZlib(str, configs): "..dR,2)end;return dE(as,nil,aY)end;function a:CompressZlibWithDict(as,aP,aY)local dQ,dR=aV(as,true,aP,true,aY)if not dQ then error("Usage: LibDeflate:CompressZlibWithDict".."(str, dictionary, configs): "..dR,2)end;return dE(as,aP,aY)end;local function dS()if os.epoch~=nil then return math.floor(os.epoch("utc")/1000)elseif os.time()<30 then return 0 else return os.time()end end;local function an(a6,R)return Y(a1(a6,R*8),0xFF)end;function a:CompressGzip(as,aY)local dQ,dR=aV(as,false,nil,true,aY)if not dQ then error("Usage: LibDeflate:CompressGzip(str, configs): "..dR,2)end;local a8,dT=dC(as,nil,aY)if a8==nil then return a8,dT end;local V=dS()local dU=0;local al=self:CRC32(as)local U=string.len(as)if aY~=nil and aY.level~=nil then if aY.level==0 then dU=0x04 elseif aY.level==9 then dU=0x02 end end;return i(0x1f,0x8b,8,0,an(V,0),an(V,1),an(V,2),an(V,3),dU,0xFF)..a8 ..i(an(al,0),an(al,1),an(al,2),an(al,3),an(U,0),an(U,1),an(U,2),an(U,3))end;local function dV(dW)local dX=dW;local dY=#dW;local dZ=1;local b8=0;local b7=0;local function d_(T)local bd=o[T]local W;if T<=b8 then W=b7%bd;b7=(b7-W)/bd;b8=b8-T else local e0=o[b8]local dN,dO,dP,e1=h(dX,dZ,dZ+3)b7=b7+((dN or 0)+(dO or 0)*256+(dP or 0)*65536+(e1 or 0)*16777216)*e0;dZ=dZ+4;b8=b8+32-T;W=b7%bd;b7=(b7-W)/bd end;return W end;local function e2(e3,ba,b6)assert(b8%8==0)local e4=b8/80 then if b8<15 and dX then local e0=o[b8]local dN,dO,dP,e1=h(dX,dZ,dZ+3)b7=b7+((dN or 0)+(dO or 0)*256+(dP or 0)*65536+(e1 or 0)*16777216)*e0;dZ=dZ+4;b8=b8+32 end;local bd=o[dy]b8=b8-dy;W=b7%bd;b7=(b7-W)/bd;W=q[dy][W]bL=e6[dy]if W0 and T285 then return-10 elseif bD<256 then b6=b6+1;ba[b6]=p[bD]elseif bD>256 then bD=bD-256;local T=x[bD]T=bD>=8 and T+d_(y[bD])or T;bD=e5(cU,el,em)if bD<0 or bD>29 then return-10 end;local X=z[bD]X=X>4 and X+d_(A[bD])or X;local eo=b6-X+1;if eo=-257 then for P=1,T do b6=b6+1;ba[b6]=ba[eo]eo=eo+1 end else eo=dx+eo;for P=1,T do b6=b6+1;ba[b6]=p[cn[eo]]eo=eo+1 end end end;if ea()<0 then return 2 end;if b6>=65536 then bb[#bb+1]=m(ba,"",1,32768)for K=32769,b6 do ba[K-32768]=ba[K]end;b6=b6-32768;ba[b6+1]=nil end until bD==256;ee.buffer_size=b6;return 0 end;local function ep(ee)local ba,b6,d_,e2,ea,eb,bb=ee.buffer,ee.buffer_size,ee.ReadBits,ee.ReadBytes,ee.ReaderBitlenLeft,ee.SkipToByteBoundary,ee.result_buffer;eb()local e3=d_(16)if ea()<0 then return 2 end;local eq=d_(16)if ea()<0 then return 2 end;if e3%256+eq%256~=255 then return-2 end;if(e3-e3%256)/256+(eq-eq%256)/256~=255 then return-2 end;b6=e2(e3,ba,b6)if b6<0 then return 2 end;if b6>=65536 then bb[#bb+1]=m(ba,"",1,32768)for K=32769,b6 do ba[K-32768]=ba[K]end;b6=b6-32768;ba[b6+1]=nil end;ee.buffer_size=b6;return 0 end;local function er(ee)return ei(ee,F,D,7,J,H,5)end;local function es(ee)local d_,e5=ee.ReadBits,ee.Decode;local et=d_(5)+257;local eu=d_(5)+1;local ev=d_(4)+4;if et>286 or eu>30 then return-3 end;local cY={}for K=1,ev do cY[B[K]]=d_(3)end;local ew,ex,ey,ez=ef(cY,18,7)if ew~=0 then return-4 end;local cS={}local cU={}local bS=0;while bSet+eu then return-6 end;while bD>0 do bD=bD-1;if bS7 then return nil,-13 end;local dK=d_(8)if ee.ReaderBitlenLeft()<0 then return nil,2 end;if(dH*256+dK)%31~=0 then return nil,-14 end;local dI=(dK-dK%32)/32%2;local dJ=(dK-dK%64)/64%4;if dI==1 then if not aP then return nil,-16 end;local dP=d_(8)local dO=d_(8)local dN=d_(8)local dM=d_(8)local aO=dP*16777216+dO*65536+dN*256+dM;if ee.ReaderBitlenLeft()<0 then return nil,2 end;if not aK(aO,aP.adler32)then return nil,-17 end end;local dD,eG=eE(ee)if not dD then return nil,eG end;ee.SkipToByteBoundary()local eL=d_(8)local eM=d_(8)local eN=d_(8)local eO=d_(8)if ee.ReaderBitlenLeft()<0 then return nil,2 end;local eP=eL*16777216+eM*65536+eN*256+eO;local eQ=a:Adler32(dD)if not aK(eP,eQ)then return nil,-15 end;local eI=ee.ReaderBitlenLeft()local eJ=(eI-eI%8)/8;return dD,eJ end;function a:DecompressDeflate(as)local dQ,dR=aV(as)if not dQ then error("Usage: LibDeflate:DecompressDeflate(str): "..dR,2)end;return eH(as)end;function a:DecompressDeflateWithDict(as,aP)local dQ,dR=aV(as,true,aP)if not dQ then error("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): "..dR,2)end;return eH(as,aP)end;function a:DecompressZlib(as)local dQ,dR=aV(as)if not dQ then error("Usage: LibDeflate:DecompressZlib(str): "..dR,2)end;return eK(as)end;function a:DecompressZlibWithDict(as,aP)local dQ,dR=aV(as,true,aP)if not dQ then error("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): "..dR,2)end;return eK(as,aP)end;do E={}for eR=0,143 do E[eR]=8 end;for eR=144,255 do E[eR]=9 end;for eR=256,279 do E[eR]=7 end;for eR=280,287 do E[eR]=8 end;I={}for X=0,31 do I[X]=5 end;local eG;eG,F,D=ef(E,287,9)assert(eG==0)eG,J,H=ef(I,31,5)assert(eG==0)C=bv(F,E,287,9)G=bv(J,I,31,5)end;function a:DecompressGzip(as)local dQ,dR=aV(as)if not dQ then error("Usage: LibDeflate:DecompressGzip(str): "..dR,2)end;if h(string.sub(as,1,1))~=31 or h(string.sub(as,2,2))~=139 then return nil,-1 end;if Y(h(string.sub(as,4,4)),0xE0)~=0 then return nil,-3 end;if h(string.sub(as,3,3))~=8 then return nil,-4 end;local c9=10;if Y(h(string.sub(as,4,4)),4)==4 then c9=c9+h(string.sub(as,11,11))*256+h(string.sub(as,12,12))end;if Y(h(string.sub(as,4,4)),8)==8 then while h(string.sub(as,c9,c9))~=0 do c9=c9+1 end end;if Y(h(string.sub(as,4,4)),16)==16 then while h(string.sub(as,c9,c9))~=0 do c9=c9+1 end end;if Y(h(string.sub(as,4,4)),2)==2 then local eS=h(string.sub(as,c9+1,c9+1))*256+h(string.sub(as,c9,c9))local eT=Y(self:CRC32(string.sub(as,1,c9-1)),0xFFFF)if _(eS,eT)~=0xFFFF then return nil,-5 end;c9=c9+2 end;local a8,dT=eH(string.sub(as,c9+1,-8))if a8==nil then return a8,dT end;local eS=h(string.sub(as,-5,-5))*0x1000000+h(string.sub(as,-6,-6))*0x10000+h(string.sub(as,-7,-7))*256+h(string.sub(as,-8,-8))eS=Z(eS)local eT=self:CRC32(a8)if _(eS,eT)~=0xFFFFFFFF then return nil,-2 end;return a8 end;local eU={["\000"]="%z",["("]="%(",[")"]="%)",["."]="%.",["%"]="%%",["+"]="%+",["-"]="%-",["*"]="%*",["?"]="%?",["["]="%[",["]"]="%]",["^"]="%^",["$"]="%$"}local function eV(as)return as:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])",eU)end;function a:CreateCodec(eW,eX,eY)if type(eW)~="string"or type(eX)~="string"or type(eY)~="string"then error("Usage: LibDeflate:CreateCodec(reserved_chars,".." escape_chars, map_chars):".." All arguments must be string.",2)end;if eX==""then return nil,"No escape characters supplied."end;if#eW<#eY then return nil,"The number of reserved characters must be".." at least as many as the number of mapped chars."end;if eW==""then return nil,"No characters to encode."end;local eZ=eW..eX..eY;local e_={}for K=1,#eZ do local an=h(eZ,K,K)if e_[an]then return nil,"There must be no duplicate characters in the".." concatenation of reserved_chars, escape_chars and".." map_chars."end;e_[an]=true end;local f0={}local f1={}local f2={}local f3={}if#eY>0 then local f4={}local f5={}for K=1,#eY do local f6=l(eW,K,K)local f7=l(eY,K,K)f3[f6]=f7;f2[#f2+1]=f6;f5[f7]=f6;f4[#f4+1]=f7 end;f0[#f0+1]="(["..eV(m(f4)).."])"f1[#f1+1]=f5 end;local f8=1;local f9=l(eX,f8,f8)local fa=0;local f4={}local f5={}for K=1,#eZ do local S=l(eZ,K,K)if not f3[S]then while fa>=256 or e_[fa]do fa=fa+1;if fa>255 then f0[#f0+1]=eV(f9).."(["..eV(m(f4)).."])"f1[#f1+1]=f5;f8=f8+1;f9=l(eX,f8,f8)fa=0;f4={}f5={}if not f9 or f9==""then return nil,"Out of escape characters."end end end;local fb=p[fa]f3[S]=f9 ..fb;f2[#f2+1]=S;f5[fb]=S;f4[#f4+1]=fb;fa=fa+1 end;if K==#eZ then f0[#f0+1]=eV(f9).."(["..eV(m(f4)).."])"f1[#f1+1]=f5 end end;local fc={}local fd="(["..eV(m(f2)).."])"local fe=f3;function fc:Encode(as)if type(as)~="string"then error(("Usage: codec:Encode(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;return k(as,fd,fe)end;local ff=#f0;local fg="(["..eV(eW).."])"function fc:Decode(as)if type(as)~="string"then error(("Usage: codec:Decode(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;if j(as,fg)then return nil end;for K=1,ff do as=k(as,f0[K],f1[K])end;return as end;return fc end;local fh;local function fi()return a:CreateCodec("\000","\001","")end;function a:EncodeForWoWAddonChannel(as)if type(as)~="string"then error(("Usage: LibDeflate:EncodeForWoWAddonChannel(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;if not fh then fh=fi()end;return fh:Encode(as)end;function a:DecodeForWoWAddonChannel(as)if type(as)~="string"then error(("Usage: LibDeflate:DecodeForWoWAddonChannel(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;if not fh then fh=fi()end;return fh:Decode(as)end;local function fj()local fa={}for K=128,255 do fa[#fa+1]=p[K]end;local eW="sS\000\010\013\124%"..m(fa)return a:CreateCodec(eW,"\029\031","\015\020")end;local fk;function a:EncodeForWoWChatChannel(as)if type(as)~="string"then error(("Usage: LibDeflate:EncodeForWoWChatChannel(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;if not fk then fk=fj()end;return fk:Encode(as)end;function a:DecodeForWoWChatChannel(as)if type(as)~="string"then error(("Usage: LibDeflate:DecodeForWoWChatChannel(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;if not fk then fk=fj()end;return fk:Decode(as)end;local fl={[0]="a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9","(",")"}local fm={[97]=0,[98]=1,[99]=2,[100]=3,[101]=4,[102]=5,[103]=6,[104]=7,[105]=8,[106]=9,[107]=10,[108]=11,[109]=12,[110]=13,[111]=14,[112]=15,[113]=16,[114]=17,[115]=18,[116]=19,[117]=20,[118]=21,[119]=22,[120]=23,[121]=24,[122]=25,[65]=26,[66]=27,[67]=28,[68]=29,[69]=30,[70]=31,[71]=32,[72]=33,[73]=34,[74]=35,[75]=36,[76]=37,[77]=38,[78]=39,[79]=40,[80]=41,[81]=42,[82]=43,[83]=44,[84]=45,[85]=46,[86]=47,[87]=48,[88]=49,[89]=50,[90]=51,[48]=52,[49]=53,[50]=54,[51]=55,[52]=56,[53]=57,[54]=58,[55]=59,[56]=60,[57]=61,[40]=62,[41]=63}function a:EncodeForPrint(as)if type(as)~="string"then error(("Usage: LibDeflate:EncodeForPrint(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;local at=#as;local fn=at-2;local K=1;local ba={}local b6=0;while K<=fn do local au,av,aw=h(as,K,K+2)K=K+3;local b7=au+av*256+aw*65536;local fo=b7%64;b7=(b7-fo)/64;local fp=b7%64;b7=(b7-fp)/64;local fq=b7%64;local fr=(b7-fq)/64;b6=b6+1;ba[b6]=fl[fo]..fl[fp]..fl[fq]..fl[fr]end;local b7=0;local b8=0;while K<=at do local ad=h(as,K,K)b7=b7+ad*o[b8]b8=b8+8;K=K+1 end;while b8>0 do local fs=b7%64;b6=b6+1;ba[b6]=fl[fs]b7=(b7-fs)/64;b8=b8-6 end;return m(ba)end;function a:DecodeForPrint(as)if type(as)~="string"then error(("Usage: LibDeflate:DecodeForPrint(str):".." 'str' - string expected got '%s'."):format(type(as)),2)end;as=as:gsub("^[%c ]+","")as=as:gsub("[%c ]+$","")local at=#as;if at==1 then return nil end;local ft=at-3;local K=1;local ba={}local b6=0;while K<=ft do local au,av,aw,ax=h(as,K,K+3)au=fm[au]av=fm[av]aw=fm[aw]ax=fm[ax]if not(au and av and aw and ax)then return nil end;K=K+4;local b7=au+av*64+aw*4096+ax*262144;local fo=b7%256;b7=(b7-fo)/256;local fp=b7%256;local fq=(b7-fp)/256;b6=b6+1;ba[b6]=p[fo]..p[fp]..p[fq]end;local b7=0;local b8=0;while K<=at do local ad=h(as,K,K)ad=fm[ad]if not ad then return nil end;b7=b7+ad*o[b8]b8=b8+6;K=K+1 end;while b8>=8 do local an=b7%256;b6=b6+1;ba[b6]=p[an]b7=(b7-an)/256;b8=b8-8 end;return m(ba)end;local function fu()fk=nil;fh=nil end;a.internals={LoadStringToTable=c6,IsValidDictionary=aT,IsEqualAdler32=aK,_byte_to_6bit_char=fl,_6bit_to_byte=fm,InternalClearCache=fu}return a diff --git a/prod/deflate/lib/deflate b/prod/deflate/lib/deflate new file mode 100644 index 0000000..4e92342 --- /dev/null +++ b/prod/deflate/lib/deflate @@ -0,0 +1,9 @@ +local deflate=require("LibDeflate") +local lib={} +lib.compress=function(data) + return deflate:CompressDeflate(data) +end +lib.decompress=function(data) + return deflate:DecompressDeflate(data) +end +return lib \ No newline at end of file diff --git a/prod/hysh/bin/chattr b/prod/hysh/bin/chattr new file mode 100644 index 0000000..a2524a3 --- /dev/null +++ b/prod/hysh/bin/chattr @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={R=false,help=false}local c={}local d=nil;for e,f in ipairs({...})do if f:sub(1,2)=="--"then local g=f:sub(3)if b[g]==nil then print(a..": unrecognized option '"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[g]=true elseif f:sub(1,1)=="-"and not f:match("^%-[%+%-]")then local h=true;for i=2,#f do local j=f:sub(i,i)if b[j]~=nil then b[j]=true else h=false;break end end;if not h then d=f end elseif f:sub(1,1)=="+"or f:sub(1,1)=="-"and f:match("^%-[a-zA-Z]")then d=f else table.insert(c,f)end end;if b.help then print("Usage: "..a.." [OPTION]... +-= ATTRS FILE...")print("Change file attributes on a filesystem.")print("")print("Attributes:")print(" i immutable: file cannot be modified, renamed, or deleted")print(" a append-only: file can only be appended to")print("")print("Operators: +attr add, -attr remove")print("Example: "..a.." +i /etc/passwd")print("")print("Options:")print(" -R operate on files and directories recursively")print(" --help display this help and exit")return end;if not d or#c<1 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local k=d:sub(1,1)local l=d:sub(2)if k~="+"and k~="-"then print(a..": invalid operator '"..k.."' (use + or -)")syscall.exit(1)return end;local function m(n)local o=pcall(function()return syscall.stat(n)end)and syscall.stat(n)if o then return o.xattr or""end;return""end;local p="|i"local q="|a"local function r(j)if j=="i"then return p elseif j=="a"then return q else return nil end end;local function s(n)local o=syscall.stat(n)if not o then print(a..": cannot stat '"..n.."': No such file or directory")return false end;if o.etype==0x01 then return true end;if not syscall.setxattr then print(a..": kernel does not expose setxattr syscall; cannot modify attributes")syscall.exit(1)return false end;local t=o.xattr or""for i=1,#l do local j=l:sub(i,i)local u=r(j)if not u then print(a..": unsupported attribute '"..j.."'")syscall.exit(1)return false end;local v=t:find(u,1,true)if k=="+"and not v then t=t..u elseif k=="-"and v then t=t:gsub(u:gsub("|","%%|"),"")end end;local w,x=pcall(syscall.setxattr,n,t)if not w then print(a..": cannot set attributes on '"..n.."': "..tostring(x))return false end;return true end;local function y(n)if not s(n)then return end;if syscall.type(n)=="directory"then local w,z=pcall(syscall.listdir,n)if w then for e,A in ipairs(z)do local B=n;if B:sub(-1)~="/"then B=B.."/"end;y(B..A)end end end end;local C=syscall.getcwd()local function D(E)if E:sub(1,1)~="/"then E=C.."/"..E end;return E end;if not syscall.setxattr then print(a..": kernel does not expose setxattr; attributes cannot be persisted")print(a..": add sys[\"setxattr\"] = vfs.setxattr to 10_vfs.kmod to enable this")syscall.exit(1)return end;local F=0;for i=1,#c do local n=D(c[i])if not syscall.exists(n)then print(a..": cannot access '"..c[i].."': No such file or directory")F=1 elseif b.R then y(n)else if not s(n)then F=1 end end end;syscall.exit(F) diff --git a/prod/hysh/bin/chgrp b/prod/hysh/bin/chgrp new file mode 100644 index 0000000..56ddee8 --- /dev/null +++ b/prod/hysh/bin/chgrp @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={R=false,help=false}local c={}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if b[f]==nil then print(a..": unrecognized option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true elseif e:sub(1,1)=="-"then for g=2,#e do local f=e:sub(g,g)if b[f]==nil then print(a..": invalid option '-"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true end else table.insert(c,e)end end;if b.help then print("Usage: "..a.." [OPTION]... GROUP FILE...")print("Change the group of each FILE to GROUP.")print("GROUP may be a group name or numeric ID.")print("")print("Options:")print(" -R operate on files and directories recursively")print(" --help display this help and exit")return end;if#c<2 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local h=c[1]local function i(j)local k=tonumber(j)if k then return k end;local l=syscall.getuidbyname and syscall.getuidbyname(j)if l then local m=syscall.getpasswd(l)if m then return m.gid end end;print(a..": invalid group: '"..j.."'")syscall.exit(1)end;local n=i(h)local function o(p)local q=syscall.stat(p)if not q then print(a..": cannot stat '"..p.."': no such file or directory")return false end;local r,s=pcall(syscall.chown,p,q.owner,n)if not r then local t=tostring(s)if t:find("EPERM")or t:find("EACCES")then t="operation not permitted (must be root)"elseif t:find("ENOENT")then t="no such file or directory"end;print(a..": cannot change group of '"..p.."': "..t)return false end;return true end;local function u(p)if not o(p)then return end;if syscall.type(p)=="directory"then local r,v=pcall(syscall.listdir,p)if r then for d,w in ipairs(v)do local x=p;if x:sub(-1)~="/"then x=x.."/"end;u(x..w)end end end end;local y=syscall.getcwd()local function z(A)if A:sub(1,1)~="/"then A=y.."/"..A end;return A end;local B=0;for g=2,#c do local p=z(c[g])if not syscall.exists(p)then print(a..": cannot access '"..c[g].."': No such file or directory")B=1 elseif b.R then u(p)else if not o(p)then B=1 end end end;syscall.exit(B) diff --git a/prod/hysh/bin/chmod b/prod/hysh/bin/chmod new file mode 100644 index 0000000..e850739 --- /dev/null +++ b/prod/hysh/bin/chmod @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={R=false,help=false}local c={}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if b[f]==nil then print(a..": unrecognized option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true elseif e:sub(1,1)=="-"then for g=2,#e do local f=e:sub(g,g)if b[f]==nil then print(a..": invalid option '-"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true end else table.insert(c,e)end end;if b.help then print("Usage: "..a.." [OPTION]... MODE FILE...")print("Change the file mode bits of each FILE to MODE.")print("")print("MODE may be octal (e.g. 755) or symbolic (e.g. u+x, go-w, a=r).")print("")print("Octal bit layout (Hyperion):")print(" owner: r=32 w=16 x=512 group: r=8 w=4 x=256")print(" world: r=2 w=1 x=128 suid=64")print(" Common: 644=rw-r--r-- 755=rwxr-xr-x 700=rwx------")print("")print("Symbolic: [ugoa][+-=][rwxs] (comma-separated list)")print("")print("Options:")print(" -R change files and directories recursively")print(" --help display this help and exit")return end;if#c<2 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local h=c[1]local i={OWNER_R=32,OWNER_W=16,OWNER_X=512,GROUP_R=8,GROUP_W=4,GROUP_X=256,WORLD_R=2,WORLD_W=1,WORLD_X=128,SUID=64}local function j(k,l)return math.floor(k/2^l)%2==1 end;local function m(n)local o=tonumber(n,8)if not o then return nil end;local p=0;if j(o,8)then p=p+i.OWNER_R end;if j(o,7)then p=p+i.OWNER_W end;if j(o,6)then p=p+i.OWNER_X end;if j(o,5)then p=p+i.GROUP_R end;if j(o,4)then p=p+i.GROUP_W end;if j(o,3)then p=p+i.GROUP_X end;if j(o,2)then p=p+i.WORLD_R end;if j(o,1)then p=p+i.WORLD_W end;if j(o,0)then p=p+i.WORLD_X end;if j(o,11)then p=p+i.SUID end;return p end;local function q(r,s)local t=s;for u in(r..","):gmatch("([^,]+),")do local v,w=u:match("^([ugoa]*)([+%-=].+)$")if not v then print(a..": invalid mode: '"..u.."'")syscall.exit(1)return nil end;if v==""or v=="a"then v="ugo"end;local x=w:sub(1,1)local y=w:sub(2)local z=0;for g=1,#y do local A=y:sub(g,g)for B=1,#v do local C=v:sub(B,B)if A=="r"then if C=="u"then z=z+i.OWNER_R elseif C=="g"then z=z+i.GROUP_R elseif C=="o"then z=z+i.WORLD_R end elseif A=="w"then if C=="u"then z=z+i.OWNER_W elseif C=="g"then z=z+i.GROUP_W elseif C=="o"then z=z+i.WORLD_W end elseif A=="x"then if C=="u"then z=z+i.OWNER_X elseif C=="g"then z=z+i.GROUP_X elseif C=="o"then z=z+i.WORLD_X end elseif A=="s"then if C=="u"then z=z+i.SUID end end end end;if x=="+"then t=t+z-(t%(z+1)-t%z>0 and 0 or 0)t=t-t%1;local function D(E,F)local p,l=0,1;while E>0 or F>0 do if E%2==1 or F%2==1 then p=p+l end;E=math.floor(E/2)F=math.floor(F/2)l=l*2 end;return p end;t=D(t,z)elseif x=="-"then local function G(E,F)local p,l=0,1;while E>0 and F>0 do if E%2==1 and F%2==1 then p=p+l end;E=math.floor(E/2)F=math.floor(F/2)l=l*2 end;return p end;local function H(E,F)local p,l=0,1;while E>0 or F>0 do if E%2==1~=(F%2==1)then p=p+l end;E=math.floor(E/2)F=math.floor(F/2)l=l*2 end;return p end;t=H(t,G(t,z))elseif x=="="then local I=0;for B=1,#v do local C=v:sub(B,B)if C=="u"then I=I+i.OWNER_R+i.OWNER_W+i.OWNER_X+i.SUID elseif C=="g"then I=I+i.GROUP_R+i.GROUP_W+i.GROUP_X elseif C=="o"then I=I+i.WORLD_R+i.WORLD_W+i.WORLD_X end end;local function H(E,F)local p,l=0,1;while E>0 or F>0 do if E%2==1~=(F%2==1)then p=p+l end;E=math.floor(E/2)F=math.floor(F/2)l=l*2 end;return p end;local function G(E,F)local p,l=0,1;while E>0 and F>0 do if E%2==1 and F%2==1 then p=p+l end;E=math.floor(E/2)F=math.floor(F/2)l=l*2 end;return p end;local function D(E,F)local p,l=0,1;while E>0 or F>0 do if E%2==1 or F%2==1 then p=p+l end;E=math.floor(E/2)F=math.floor(F/2)l=l*2 end;return p end;t=H(t,G(t,I))t=D(t,z)else print(a..": invalid operator in mode: '"..u.."'")syscall.exit(1)return nil end end;return t end;local function J(r,s)if r:match("^[0-7]+$")then local K=m(r)if K then return K end end;return q(r,s)end;local function L(M)local N,O=pcall(syscall.stat,M)local s=0;if N then local n=syscall.stat(M)s=n and n.perms or 0 end;local P=J(h,s)if P==nil then return false end;local Q,R=pcall(syscall.chmod,M,P)if not Q then local S=tostring(R)if S:find("EACCES")or S:find("EPERM")then S="permission denied"elseif S:find("ENOENT")then S="no such file or directory"end;print(a..": cannot change permissions of '"..M.."': "..S)return false end;return true end;local function T(M)if not L(M)then return end;if syscall.type(M)=="directory"then local Q,U=pcall(syscall.listdir,M)if Q then for d,V in ipairs(U)do local W=M;if W:sub(-1)~="/"then W=W.."/"end;T(W..V)end end end end;local X=syscall.getcwd()local function Y(K)if K:sub(1,1)~="/"then K=X.."/"..K end;return K end;local Z=0;for g=2,#c do local M=Y(c[g])if not syscall.exists(M)then print(a..": cannot access '"..c[g].."': No such file or directory")Z=1 elseif b.R then T(M)else if not L(M)then Z=1 end end end;syscall.exit(Z) diff --git a/prod/hysh/bin/chown b/prod/hysh/bin/chown new file mode 100644 index 0000000..788e233 --- /dev/null +++ b/prod/hysh/bin/chown @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={R=false,help=false}local c={}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if b[f]==nil then print(a..": unrecognized option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true elseif e:sub(1,1)=="-"then for g=2,#e do local f=e:sub(g,g)if b[f]==nil then print(a..": invalid option '-"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true end else table.insert(c,e)end end;if b.help then print("Usage: "..a.." [OPTION]... OWNER[:GROUP] FILE...")print(" "..a.." [OPTION]... :GROUP FILE...")print("Change the owner and/or group of each FILE.")print("OWNER and GROUP may be names or numeric IDs.")print("")print("Options:")print(" -R operate on files and directories recursively")print(" --help display this help and exit")return end;if#c<2 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local h=c[1]local i,j;if h:sub(1,1)==":"then j=h:sub(2)else local k=h:find(":",1,true)if k then i=h:sub(1,k-1)j=h:sub(k+1)if j==""then j=nil end else i=h end end;local function l(m)if not m or m==""then return nil end;local n=tonumber(m)if n then return n end;local o=syscall.getuidbyname and syscall.getuidbyname(m)if o then return o end;print(a..": invalid user: '"..m.."'")syscall.exit(1)end;local function p(m)if not m or m==""then return nil end;local n=tonumber(m)if n then return n end;local o=syscall.getuidbyname and syscall.getuidbyname(m)if o then local q=syscall.getpasswd(o)if q then return q.gid end end;print(a..": invalid group: '"..m.."'")syscall.exit(1)end;local r=l(i)local s=p(j)if r==nil and s==nil then print(a..": no owner or group specified")syscall.exit(1)return end;local function t(u)local v=syscall.stat(u)if not v then print(a..": cannot stat '"..u.."': no such file or directory")return false end;local o=r~=nil and r or v.owner;local w=s~=nil and s or v.group;local x,y=pcall(syscall.chown,u,o,w)if not x then local z=tostring(y)if z:find("EPERM")or z:find("EACCES")then z="operation not permitted (must be root)"elseif z:find("ENOENT")then z="no such file or directory"end;print(a..": cannot change owner of '"..u.."': "..z)return false end;return true end;local function A(u)if not t(u)then return end;if syscall.type(u)=="directory"then local x,B=pcall(syscall.listdir,u)if x then for d,C in ipairs(B)do local D=u;if D:sub(-1)~="/"then D=D.."/"end;A(D..C)end end end end;local E=syscall.getcwd()local function F(G)if G:sub(1,1)~="/"then G=E.."/"..G end;return G end;local H=0;for g=2,#c do local u=F(c[g])if not syscall.exists(u)then print(a..": cannot access '"..c[g].."': No such file or directory")H=1 elseif b.R then A(u)else if not t(u)then H=1 end end end;syscall.exit(H) diff --git a/prod/hysh/bin/chroot b/prod/hysh/bin/chroot new file mode 100644 index 0000000..0fd573a --- /dev/null +++ b/prod/hysh/bin/chroot @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={}local c={help=false}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if f=="help"then c.help=true else print(a..": unrecognized option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end elseif e:sub(1,1)=="-"then print(a..": invalid option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return else table.insert(b,e)end end;if c.help then print("Usage: "..a.." NEWROOT [COMMAND [ARG]...]")print("Run COMMAND with root directory set to NEWROOT.")print("If COMMAND is omitted, runs the current user's shell.")print("")print("Requires root (uid 0).")return end;if#b<1 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local g=syscall.geteuid and syscall.geteuid()or syscall.getuid()if g~=0 then print(a..": cannot change root directory: Permission denied")syscall.exit(1)return end;local h=b[1]if h:sub(1,1)~="/"then h=syscall.getcwd().."/"..h end;if not syscall.exists(h)then print(a..": cannot change root directory to '"..b[1].."': No such file or directory")syscall.exit(1)return end;if syscall.type(h)~="directory"then print(a..": '"..b[1].."': Not a directory")syscall.exit(1)return end;local i,j=pcall(syscall.chroot,h)if not i then print(a..": cannot change root directory to '"..b[1].."': "..tostring(j))syscall.exit(1)return end;local k;if#b>=2 then k=b[2]else local l=syscall.getuid()local m=syscall.getpasswd(l)k=m and m.shell or"/bin/hysh"end;local n={}for o=3,#b do table.insert(n,b[o])end;local p,q=pcall(syscall.exec,k,n)if not p then print(a..": failed to run command '"..k.."': "..tostring(q))syscall.exit(127)end diff --git a/prod/hysh/bin/help b/prod/hysh/bin/help new file mode 100644 index 0000000..a814d38 --- /dev/null +++ b/prod/hysh/bin/help @@ -0,0 +1 @@ +local a={{name="cd",usage="cd [dir]",desc="Change working directory. Use '-' to return to previous directory.",flags={}},{name="pwd",usage="pwd",desc="Print current working directory.",flags={}},{name="ls",usage="ls [-alh] [dir]",desc="List directory contents. Coloured by type: dirs=blue, symlinks=cyan, executables=green.",flags={{"-a","Show hidden files (starting with .)"},{"-l","Long format: permissions, owner, group, size, mtime, name"},{"-h","Human-readable file sizes (with -l)"},{"--help","Display help and exit"}}},{name="find",usage="find [path] [-name PAT] [-type f|d|l] [-maxdepth N]",desc="Walk the filesystem tree and print matching paths.",flags={{"-name PAT","Match filename against shell glob (* and ?)"},{"-type f|d|l","Filter by file, directory, or symlink"},{"-maxdepth N","Descend at most N directory levels"},{"-mindepth N","Skip entries shallower than N levels"},{"-empty","Match empty files or empty directories"}}},{name="cp",usage="cp [-rRp] SOURCE... DEST",desc="Copy files or directories.",flags={{"-r,-R","Recurse into directories"},{"-p","Preserve permissions"},{"--help","Display help and exit"}}},{name="mv",usage="mv [-f] SOURCE... DEST",desc="Move or rename files and directories.",flags={{"-f","Do not prompt before overwriting (default)"},{"--help","Display help and exit"}}},{name="rm",usage="rm [-rRf] FILE...",desc="Remove files or directories.",flags={{"-r,-R","Recursively remove directories and their contents"},{"-f","Ignore nonexistent files, never prompt"},{"--help","Display help and exit"}}},{name="touch",usage="touch FILE...",desc="Create an empty file, or no-op if it already exists.",flags={}},{name="mkdir",usage="mkdir ",desc="Create a directory.",flags={}},{name="ln",usage="ln -s [-f] TARGET LINK",desc="Create a symbolic link. Multiple targets can be linked into a directory.",flags={{"-s","Create a symbolic link (required; hard links not supported)"},{"-f","Remove existing destination before creating link"},{"--help","Display help and exit"}}},{name="cat",usage="cat [file...]",desc="Print file(s) to stdout. Reads stdin if no file given.",flags={}},{name="head",usage="head [-n N] [file...]",desc="Print the first N lines of each file (default 10).",flags={{"-n N","Number of lines to print"},{"--help","Display help and exit"}}},{name="tail",usage="tail [-n N] [file...]",desc="Print the last N lines of each file (default 10).",flags={{"-n N","Number of lines to print"},{"--help","Display help and exit"}}},{name="wc",usage="wc [-lwc] [file...]",desc="Count lines, words, and bytes in files.",flags={{"-l","Print line count"},{"-w","Print word count"},{"-c","Print byte count"},{"--help","Display help and exit"}}},{name="grep",usage="grep [-ivnlcrR] PATTERN [file...]",desc="Search for lines matching a Lua pattern.",flags={{"-i","Ignore case"},{"-v","Invert: select non-matching lines"},{"-n","Prefix output with line numbers"},{"-l","Print only filenames that contain a match"},{"-c","Print count of matching lines per file"},{"-r,-R","Recurse into directories"},{"--help","Display help and exit"}}},{name="sed",usage="sed 's/PAT/REPL/' [file...]",desc="Stream editor. Applies substitution commands to each line.",flags={}},{name="sort",usage="sort [-rnu] [file...]",desc="Sort lines of text.",flags={{"-r","Reverse the sort order"},{"-n","Numeric sort"},{"-u","Suppress duplicate lines"},{"--help","Display help and exit"}}},{name="uniq",usage="uniq [-cdui] [input [output]]",desc="Filter adjacent duplicate lines.",flags={{"-c","Prefix each line with its repetition count"},{"-d","Print only lines that appear more than once"},{"-u","Print only lines that appear exactly once"},{"-i","Ignore case when comparing"},{"--help","Display help and exit"}}},{name="tee",usage="tee [-a] [file...]",desc="Copy stdin to stdout and to each FILE simultaneously.",flags={{"-a","Append to files instead of overwriting"},{"--help","Display help and exit"}}},{name="basename",usage="basename STRING [SUFFIX]",desc="Strip directory and optional suffix from a path.",flags={}},{name="dirname",usage="dirname STRING...",desc="Strip the last component from a path.",flags={}},{name="readlink",usage="readlink [-fenq] file...",desc="Print the target of a symbolic link.",flags={{"-f","Canonicalize: follow every symlink component"},{"-e","Like -f but all components must exist"},{"-n","Do not output trailing newline"},{"--help","Display help and exit"}}},{name="stat",usage="stat file...",desc="Display file type, size, owner, group, and permissions.",flags={{"--help","Display help and exit"}}},{name="chmod",usage="chmod [-R] MODE file...",desc="Change file permissions. MODE may be octal (755) or symbolic (u+x).",flags={{"-R","Recurse into directories"},{"--help","Display help and exit"}}},{name="chown",usage="chown [-R] USER[:GROUP] file...",desc="Change file owner and/or group.",flags={{"-R","Recurse into directories"},{"--help","Display help and exit"}}},{name="chgrp",usage="chgrp [-R] GROUP file...",desc="Change file group ownership.",flags={{"-R","Recurse into directories"},{"--help","Display help and exit"}}},{name="chattr",usage="chattr [+-=][attrs] file...",desc="Change file attributes.",flags={}},{name="echo",usage="echo [text...]",desc="Print arguments to stdout.",flags={}},{name="whoami",usage="whoami",desc="Print the current username.",flags={}},{name="id",usage="id [username]",desc="Print user identity (uid, gid).",flags={}},{name="ps",usage="ps",desc="List running tasks with pid, user, name, and status.",flags={}},{name="hostname",usage="hostname [NAME]",desc="Print or set the system hostname.",flags={}},{name="uname",usage="uname [-asnrm]",desc="Print system information (OS name, hostname, release, machine).",flags={{"-a","Print all fields"},{"-s","Kernel name"},{"-n","Node hostname"},{"-r","Kernel release"},{"-m","Machine hardware name"},{"--help","Display help and exit"}}},{name="df",usage="df [-h] [path...]",desc="Report filesystem disk space usage.",flags={{"-h","Human-readable sizes (K, M, G)"},{"--help","Display help and exit"}}},{name="stat",usage="stat file...",desc="Display file status: type, size, permissions, owner.",flags={}},{name="env",usage="env [KEY=VAL]... [CMD]",desc="Print the environment, or run a command with modified environment.",flags={}},{name="printenv",usage="printenv [NAME...]",desc="Print environment variable values (all if no names given).",flags={}},{name="sleep",usage="sleep N[smhd]",desc="Pause for N seconds (or minutes/hours/days with m/h/d suffix).",flags={}},{name="true",usage="true",desc="Do nothing, exit successfully (status 0).",flags={}},{name="false",usage="false",desc="Do nothing, exit unsuccessfully (status 1).",flags={}},{name="yes",usage="yes [text]",desc="Repeatedly print 'y' (or given text) until interrupted.",flags={}},{name="mount",usage="mount [-o loop] [SRC DEST | ID MNT]",desc="Mount a loop device or show all current mounts.",flags={{"-o loop","Attach SRC as a loop device and mount at DEST in one step"},{"--help","Display help and exit"}}},{name="umount",usage="umount [--no-detach] MOUNTPOINT | -l LOOPID",desc="Unmount a filesystem and auto-detach its loop device.",flags={{"--no-detach","Unmount but keep loop device attached"},{"-l LOOPID","Force-detach a loop device without unmounting"},{"--help","Display help and exit"}}},{name="losetup",usage="losetup [-dil] [path]",desc="Attach a directory or .hfs image as a loop device.",flags={{"-d ID","Detach loop device"},{"-i path","Force image mode (even without .hfs extension)"},{"-l","List all attached loop devices"},{"--help","Display help and exit"}}},{name="loimgcreate",usage="loimgcreate [-x] SRC DEST",desc="Pack a directory into a portable HFS image, or extract one.",flags={{"-x","Extract image to destination directory"},{"--help","Display help and exit"}}},{name="useradd",usage="useradd [-p pw] [-g gid] [-d home] [-s shell] [-M] ",desc="Create a new user account.",flags={{"-p pw","Set password"},{"-g gid","Set primary group id"},{"-d home","Set home directory (default /home/username)"},{"-s shell","Set login shell (default /bin/hysh)"},{"-M","Do not create home directory"}}},{name="userdel",usage="userdel [-r] ",desc="Delete a user account.",flags={{"-r","Also remove the user's home directory"}}},{name="usermod",usage="usermod [-l name] [-p pw] [-g gid] [-d home] [-s shell] [-LU] ",desc="Modify an existing user account.",flags={{"-l name","Rename the user"},{"-p pw","Set new password"},{"-g gid","Change primary group id"},{"-d home","Change home directory"},{"-s shell","Change login shell"},{"-L","Lock the account"},{"-U","Unlock the account"}}},{name="passwd",usage="passwd [username]",desc="Change a user password.",flags={}},{name="lsusers",usage="lsusers",desc="List all user accounts with uid, gid, home, and shell.",flags={}},{name="su",usage="su [username]",desc="Switch user. Defaults to root. Root can switch without a password.",flags={}},{name="sudo",usage="sudo [-u user] CMD [args...]",desc="Run a command as another user (default root).",flags={{"-u user","Run as the specified user (name or uid)"}}},{name="exit",usage="exit [N]",desc="Exit the shell with optional status code N.",flags={}},{name="clear",usage="clear",desc="Clear the terminal screen.",flags={}},{name="help",usage="help [command]",desc="Display this command reference. Pass a command name to filter.",flags={}},{name="lua",usage="lua",desc="Interactive Lua REPL prompt.",flags={}},{name="micro",usage="micro [file]",desc="Full-screen terminal text editor.",flags={}},{name="hfetch",usage="hfetch",desc="Display system information in a neofetch-style layout.",flags={}},{name="sysdump",usage="sysdump",desc="List all registered kernel syscalls.",flags={}},{name="chroot",usage="chroot DIR [CMD]",desc="Run a command with a different root directory.",flags={}}}do local b={}local c={}for d,e in ipairs(a)do if not b[e.name]then b[e.name]=true;table.insert(c,e)end end;a=c end;local f=7;local g=5;local h=1;local i=13;local j=3;local k=12;local l={}local function m(n,o)l[#l+1]={n,o or 1}end;m("HyperionOS Command Reference",f)m(string.rep("=",50),k)m("",1)local p={...}local q=p[1]local function r(e)m(e.name,g)m(" Usage: "..e.usage,h)m(" "..e.desc,i)if#e.flags>0 then for d,s in ipairs(e.flags)do m(" "..s[1],j)m(" "..s[2],i)end end;m("",1)end;if q then local t=false;for d,e in ipairs(a)do if e.name==q then r(e)t=true;break end end;if not t then m("help: unknown command '"..q.."'",2)m("Run 'help' with no arguments for the full list.",i)end else m("Run 'help ' for details on a specific command.",i)m("",1)for d,e in ipairs(a)do r(e)end end;local u=syscall.devctl(1,"size")local v=tonumber(u:match("^(%d+)"))or 51;local w=tonumber(u:match(";(%d+)"))or 19;local x=w-2;local y=0;local z=#l;local A=true;local function B()syscall.devctl(1,"clear")syscall.devctl(1,"spos",1,1)for C=1,x do local D=y+C;if D<=z then local n,o=l[D][1],l[D][2]syscall.devctl(1,"sfgc",o)if#n>v then n=n:sub(1,v)end;syscall.write(1,n.."\n")else syscall.write(1,"\n")end end;syscall.devctl(1,"sfgc",0x000000)syscall.devctl(1,"sbgc",0xDBDBDB)local E=math.floor(math.min(100,(y+x)/z*100))local F=string.format(" help -- line %d/%d (%d%%) [up/down: scroll q: quit] ",y+1,z,E)if#F>v then F=F:sub(1,v)end;syscall.devctl(1,"spos",1,w)syscall.write(1,F..string.rep(" ",v-#F))syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"sbgc",0x000000)A=false end;if z<=x then syscall.devctl(1,"clear")syscall.devctl(1,"spos",1,1)for d,G in ipairs(l)do syscall.devctl(1,"sfgc",G[2])syscall.write(1,G[1].."\n")end;syscall.devctl(1,"sfgc",0xFFFFFF)return end;B()while true do local H=syscall.read(0)if not H or H==""then elseif H=="q"or H=="Q"then break elseif H=="\17"then if y>0 then y=y-1;A=true end elseif H=="\18"then if y+x0 then q[#q+1]=p.."d"end;if o>0 then q[#q+1]=o.."h"end;if n>0 then q[#q+1]=n.."m"end;q[#q+1]=m.."s"return table.concat(q," ")end;local r=syscall.getHost()or"Unknown"local s=r:match("ComputerCraft ([%d%.]+)")or r;local t={{nil,j},{nil,string.rep("-",#j)},{"OS",syscall.version()or"Unknown"},{"Host",s},{"Arch",syscall.arch()or"Unknown"},{"Uptime",k(syscall.getUptime()or 0)},{"Tasks",tostring(#(syscall.getTasks()or{}))},{"Shell",syscall.getEnviron("SHELL")or"Unknown"},{"Terminal","tty1"},{"UID",tostring(syscall.getuid())},{"Packages","n/a (spm)"}}local u={".. *. .. "," *= +@* +* "," .@#. -@@@= :#@. "," =@@+ *@@@# +@@= "," %@@%: *@@@# -%@@% "," :@@@@+ *@@@# .*@@@@: "," :*@@@%- *@@@# -@@@@*: "," =%@@#. *@@@# .#@@%= "," :=. :*@@= *@@@# =@@+: .=: "," %@#=..*# +@@@# #*..=#@# "," .@@@@+=# .%@%: #=+@@@@. "," .....=# -@= *+...:. "," -*%*-@= - =@-*%*- "," -@*. -@%. :%@- :*@- "," .#@#@* "," -#- "," "}local v=math.max(#u,#t)for w=1,v do local x=u[w]or string.rep(" ",36)f(a)printInline(x)f(c)printInline("| ")local y=t[w]if y then if y[1]==nil and w==1 then f(e)printInline(y[2])elseif y[1]==nil and w==2 then f(d)printInline(y[2])elseif y[1]then f(c)printInline(y[1]..": ")f(b)printInline(y[2])end end;f(b)print("")end diff --git a/prod/hysh/bin/hysh b/prod/hysh/bin/hysh new file mode 100644 index 0000000..5a0e737 --- /dev/null +++ b/prod/hysh/bin/hysh @@ -0,0 +1 @@ +syscall.open("/dev/tty/1","r")syscall.open("/dev/tty/1","w")syscall.open("/dev/null","w")local a,b=xpcall(function()local c=require("fs")syscall.devctl(1,"clear")syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"spos",1,1)print("HyperionOS hysh Shell")local d=(syscall.getUsername()or"Unknown").."@"..(syscall.getHostname()or"Unknown")local e={}local f=false;syscall.setEnviron("SHELL","hysh")syscall.setEnviron("PATH","/bin/")local g=syscall.getEnviron("HOME")if g and g~=""then local h=pcall(syscall.chdir,g)if not h then syscall.chdir("/")end else syscall.chdir("/")end;local i=""local j={0xFFFFFF,0xFF0000,0x00FF00,0x0000FF,0x00FFFF,0xFF00FF,0xFFFF00,0xFF6D00,0x6DFF55,0x24FFFF,0x924900,0x6D6D55,0xDBDBAA,0x6D00FF,0xB6FF00,0x000000}for k=1,16 do syscall.devctl(1,"sbgc",j[k])printInline(" ")end;print("\n")syscall.sigcatch(function(l)if l==1 then f=true end end)local function m(n)if not n or n==""then return syscall.getcwd()end;if n:sub(1,1)~="/"then n=syscall.getcwd().."/"..n end;local o={}for p in n:gmatch("[^/]+")do if p==".."then if#o>0 then table.remove(o)end elseif p~="."then table.insert(o,p)end end;return"/"..table.concat(o,"/")end;local function q(n)n=n:gsub("/$","")return n:match("([^/]+)$")or n end;local function r(n)n=n:gsub("/$","")local s=n:match("^(.*)/[^/]+$")if not s then return"."end;if s==""then return"/"end;return s end;local function t(u)local v={}while true do local h,w=pcall(syscall.read,u,65536)if not h or not w or w==""then break end;v[#v+1]=w end;return table.concat(v)end;local function x(y)local h,u=pcall(syscall.open,y,"r")if not h then return nil,u end;local z=t(u)pcall(syscall.close,u)return z end;local function A(y,z)local h,u=pcall(syscall.open,y,"w")if not h then return false,u end;pcall(syscall.write,u,z)pcall(syscall.close,u)return true end;local function B(C,D,E)local F={}local G={}E=E or{}local k=1;while k<=#C do local H=C[k]if H=="--"then for I=k+1,#C do G[#G+1]=C[I]end;break elseif H:sub(1,2)=="--"then local J=H:sub(3)if E[J]~=nil then F[J]=true else F["_unknown"]=H end elseif H:sub(1,1)=="-"and#H>1 then for K=2,#H do local L=H:sub(K,K)if D:find(L,1,true)then F[L]=true else F["_unknown"]="-"..L end end else G[#G+1]=H end;k=k+1 end;return F,G end;local function M(N,O)local P=1;while P<=#N do local Q=N:find("\n",P,true)if Q then O(N:sub(P,Q-1))P=Q+1 else O(N:sub(P))break end end end;local function R(N)local S={}M(N,function(T)S[#S+1]=T end)return S end;local function U(V,W)local z,X=x(V)if not z then return false,X end;local h,Y=A(W,z)if not h then return false,Y end;return true end;local function Z(y)local v=syscall.type(y)if v=="directory"then local h,_=pcall(syscall.listdir,y)if h then for a0,a1 in ipairs(_)do Z(y:gsub("/$","").."/"..a1)end end end;if v then pcall(syscall.remove,y)end end;local function a2(V,W)pcall(syscall.mkdir,W)local h,_=pcall(syscall.listdir,V)if not h then return end;for a0,a1 in ipairs(_)do local a3=V:gsub("/$","").."/"..a1;local s=W:gsub("/$","").."/"..a1;local v=syscall.type(a3)if v=="directory"then a2(a3,s)elseif v=="file"then U(a3,s)elseif v=="symlink"then local a4,a5=pcall(syscall.readlink,a3)if a4 then pcall(syscall.remove,s)pcall(syscall.symlink,a5,s)end end end end;local a6={}a6.cd=function(y)local a7=syscall.getcwd()local a8=y or""if a8=="-"then if i==""then print("hysh: cd: no previous directory")return end;print(i)local a9=i;i=a7;syscall.chdir(a9)return end;local aa=m(a8)if aa:sub(-1)~="/"then aa=aa.."/"end;if not c.isDir(aa)then print("hysh: cd: "..a8 ..": No such directory")return end;i=a7;syscall.chdir(aa)end;a6.exit=function(ab)syscall.exit(tonumber(ab)or 0)end;a6.echo=function(...)local G={...}local ac=false;local ad=1;if G[1]=="-n"then ac=true;ad=2 end;local ae=table.concat(G," ",ad)if ac then printInline(ae)else print(ae)end end;a6.pwd=function()print(syscall.getcwd())end;a6["true"]=function()end;a6["false"]=function()end;a6.sleep=function(...)local G={...}if#G==0 then print("sleep: missing operand")return end;local af=0;for a0,ag in ipairs(G)do local ac,ah=ag:match("^([%d%.]+)([smhd]?)$")if not ac then print("sleep: invalid time '"..ag.."'")return end;ac=tonumber(ac)if ah=="m"then ac=ac*60 elseif ah=="h"then ac=ac*3600 elseif ah=="d"then ac=ac*86400 end;af=af+ac end;sleep(af)end;a6.clear=function()syscall.devctl(1,"clear")syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"spos",1,1)end;a6.whoami=function()print(syscall.getUsername()or"unknown")end;a6.hostname=function(...)local G={...}if#G==0 then print(syscall.getHostname()or"unknown")else local h,X=pcall(syscall.setHostname,G[1])if not h then print("hostname: "..tostring(X))end end end;a6.uname=function(...)local F,a0=B({...},"asnrm")local ai=F.a;local o={}local aj={}for ak in string.gmatch(syscall.version(),"%S+")do table.insert(aj,ak)end;if ai or F.s or not F.s and not F.n and not F.r and not F.m then o[#o+1]=aj[1]end;if ai or F.n then o[#o+1]=syscall.getHostname()or"hyperion"end;if ai or F.r then o[#o+1]=aj[2]end;if ai or F.m then o[#o+1]="virtual"end;print(table.concat(o," "))end;a6.printenv=function(...)local G={...}local al={"PATH","HOME","USER","SHELL","TERM","HOSTNAME","PWD","OLDPWD","LANG","TZ","EDITOR"}if#G==0 then for a0,K in ipairs(al)do local h,H=pcall(syscall.getEnviron,K)if h and H then print(K.."="..H)end end else for a0,K in ipairs(G)do local h,H=pcall(syscall.getEnviron,K)if h and H then print(H)end end end end;a6.env=function(...)local G={...}local k=1;while k<=#G and G[k]:match("^[%w_]+=")do local K,H=G[k]:match("^([^=]+)=(.*)")pcall(syscall.setEnviron,K,H)k=k+1 end;if k>#G then a6.printenv()end end;a6.touch=function(...)local a0,G=B({...},"amc")if#G==0 then print("touch: missing operand")return end;for a0,ag in ipairs(G)do local y=m(ag)if not syscall.exists(y)then local h,u=pcall(syscall.open,y,"w")if h then pcall(syscall.close,u)else print("touch: cannot create '"..ag.."': "..tostring(u))end end end end;a6.mkdir=function(...)local F,G=B({...},"p")if#G==0 then print("mkdir: missing operand")return end;for a0,ag in ipairs(G)do local y=m(ag)if y:sub(-1)~="/"then y=y.."/"end;if c.isDir(y)then print("mkdir: cannot create '"..ag.."': Directory exists")return end;local h,X=pcall(syscall.mkdir,y)if not h then print("mkdir: cannot create '"..ag.."': "..tostring(X))end end end;a6.rm=function(...)local F,G=B({...},"rRf")if#G==0 then print("rm: missing operand")return end;local am=F.r or F.R;for a0,ag in ipairs(G)do local y=m(ag)local v=syscall.type(y)if not v then if not F.f then print("rm: cannot remove '"..ag.."': No such file or directory")end elseif v=="directory"then if not am then print("rm: cannot remove '"..ag.."': Is a directory")else Z(y)end else local h,X=pcall(syscall.remove,y)if not h then print("rm: cannot remove '"..ag.."': "..tostring(X))end end end end;a6.cp=function(...)local F,G=B({...},"rRp")if#G<2 then print("cp: missing operand")return end;local am=F.r or F.R;local W=m(G[#G])local an=syscall.type(W)=="directory"if#G>2 and not an then print("cp: target '"..G[#G].."' is not a directory")return end;for k=1,#G-1 do local V=m(G[k])local v=syscall.type(V)if not v then print("cp: '"..G[k].."': No such file or directory")elseif v=="directory"then if not am then print("cp: omitting directory '"..G[k].."'")else a2(V,an and W:gsub("/$","").."/"..q(G[k])or W)end else local s=an and W:gsub("/$","").."/"..q(G[k])or W;local h,X=U(V,s)if not h then print("cp: '"..G[k].."': "..tostring(X))end end end end;a6.mv=function(...)local F,G=B({...},"f")if#G<2 then print("mv: missing operand")return end;local W=m(G[#G])local an=syscall.type(W)=="directory"if#G>2 and not an then print("mv: target '"..G[#G].."' is not a directory")return end;for k=1,#G-1 do local V=m(G[k])local v=syscall.type(V)if not v then print("mv: '"..G[k].."': No such file or directory")else local s=an and W:gsub("/$","").."/"..q(G[k])or W;if v=="directory"then a2(V,s)Z(V)else local h,X=U(V,s)if h then pcall(syscall.remove,V)else print("mv: '"..G[k].."': "..tostring(X))end end end end end;a6.cat=function(...)local G={...}if#G==0 then while true do local h,w=pcall(syscall.read,0,4096)if not h or not w or w==""then break end;printInline(w)end;print("")return end;for a0,ag in ipairs(G)do local y=m(ag)if not syscall.exists(y)then print("cat: "..ag..": No such file or directory")else local h,u=pcall(syscall.open,y,"r")if not h then print("cat: "..ag..": "..tostring(u))else while true do local a4,w=pcall(syscall.read,u,65536)if not a4 or not w or w==""then break end;printInline(w)end;pcall(syscall.close,u)end end end end;a6.head=function(...)local ao={...}local ac=10;local ap={}local k=1;while k<=#ao do local H=ao[k]if H=="-n"then k=k+1;ac=tonumber(ao[k])or 10 elseif H:match("^%-n%d+$")then ac=tonumber(H:sub(3))elseif H:match("^%-%d+$")then ac=tonumber(H:sub(2))elseif H:sub(1,1)~="-"or H=="-"then ap[#ap+1]=H end;k=k+1 end;local aq=#ap>1;local function ar(N,as)if aq then syscall.devctl(1,"sfgc",0x0000FF)print("==> "..as.." <==")syscall.devctl(1,"sfgc",0xFFFFFF)end;local at=0;for au in(N.."\n"):gmatch("([^\n]*)\n")do if at>=ac then break end;print(au)at=at+1 end end;if#ap==0 then ar(t(0),"stdin")else for a0,ag in ipairs(ap)do if ag=="-"then ar(t(0),"stdin")else local z,X=x(m(ag))if not z then print("head: "..ag..": "..tostring(X))else ar(z,ag)end end end end end;a6.tail=function(...)local ao={...}local ac=10;local ap={}local k=1;while k<=#ao do local H=ao[k]if H=="-n"then k=k+1;ac=tonumber(ao[k])or 10 elseif H:match("^%-n%d+$")then ac=tonumber(H:sub(3))elseif H:match("^%-%d+$")then ac=tonumber(H:sub(2))elseif H:sub(1,1)~="-"or H=="-"then ap[#ap+1]=H end;k=k+1 end;local aq=#ap>1;local function av(N,as)if aq then syscall.devctl(1,"sfgc",0x0000FF)print("==> "..as.." <==")syscall.devctl(1,"sfgc",0xFFFFFF)end;local S=R(N)local ad=math.max(1,#S-ac+1)for I=ad,#S do print(S[I])end end;if#ap==0 then av(t(0),"stdin")else for a0,ag in ipairs(ap)do if ag=="-"then av(t(0),"stdin")else local z,X=x(m(ag))if not z then print("tail: "..ag..": "..tostring(X))else av(z,ag)end end end end end;a6.wc=function(...)local F,G=B({...},"lwc")local aw=not F.l and not F.w and not F.c;if aw then F.l=true;F.w=true;F.c=true end;local function at(N)local T,ax,ay=0,0,#N;for a0 in N:gmatch("\n")do T=T+1 end;for a0 in N:gmatch("%S+")do ax=ax+1 end;return T,ax,ay end;local function az(T,ax,L,aA)local n={}if F.l then n[#n+1]=string.format("%7d",T)end;if F.w then n[#n+1]=string.format("%7d",ax)end;if F.c then n[#n+1]=string.format("%7d",L)end;if aA then n[#n+1]=" "..aA end;print(table.concat(n))end;local aB,aC,aD=0,0,0;if#G==0 then local T,ax,L=at(t(0))az(T,ax,L)else for a0,ag in ipairs(G)do local z,X=x(m(ag))if not z then print("wc: "..ag..": "..tostring(X))else local T,ax,L=at(z)az(T,ax,L,ag)aB=aB+T;aC=aC+ax;aD=aD+L end end;if#G>1 then az(aB,aC,aD,"total")end end end;a6.grep=function(...)local F,G=B({...},"ivnlcrR",{["ignore-case"]=true,["invert-match"]=true})if#G==0 then print("grep: missing pattern")return end;local aE=G[1]if F.i or F["ignore-case"]then aE=aE:lower()end;local am=F.r or F.R;local aF=false;local function aG(N,as,aH)local at=0;local aI=0;local aJ=false;M(N,function(au)aI=aI+1;local aK=(F.i or F["ignore-case"])and au:lower()or au;local aL=aK:find(aE)~=nil;if F.v or F["invert-match"]then aL=not aL end;if aL then at=at+1;aJ=true;aF=true;if not F.l and not F.c then local ae=""if aH then ae=ae..as..":"end;if F.n then ae=ae..aI..":"end;print(ae..au)end end end)if F.l and aJ then print(as)end;if F.c then print((aH and as..":"or"")..at)end end;local function aM(y,as,aH)local z,X=x(y)if not z then print("grep: "..as..": "..tostring(X))return end;aG(z,as,aH)end;local function aN(aO,aP)local h,_=pcall(syscall.listdir,aO)if not h then return end;for a0,a1 in ipairs(_)do local aQ=aO:gsub("/$","").."/"..a1;local aA=(aP~=""and aP.."/"or"")..a1;local v=syscall.type(aQ)if v=="directory"then aN(aQ,aA)elseif v=="file"then aM(aQ,aA,true)end end end;if#G==1 then aG(t(0),"(stdin)",false)else local aH=#G>2 or am;for k=2,#G do local y=m(G[k])local v=syscall.type(y)if v=="directory"then if am then aN(y,G[k])else print("grep: "..G[k]..": Is a directory")end elseif v then aM(y,G[k],aH)else print("grep: "..G[k]..": No such file or directory")end end end end;a6.sort=function(...)local F,G=B({...},"rnu")local S={}local function aR(N)local aS=R(N)for a0,T in ipairs(aS)do S[#S+1]=T end end;if#G==0 then aR(t(0))else for a0,ag in ipairs(G)do local z,X=x(m(ag))if not z then print("sort: "..ag..": "..tostring(X))else aR(z)end end end;table.sort(S,function(ag,ay)if F.n then local aT=tonumber(ag:match("^%-?%d+%.?%d*"))or 0;local aU=tonumber(ay:match("^%-?%d+%.?%d*"))or 0;return F.r and aT>aU or aTay or ag1 then return end;ae[#ae+1]=F.c and string.format("%7d %s",at,au)or au end;M(N,function(au)local aY=F.i and au:lower()or au;local aZ=F.i and(aV and aV:lower())or aV;if aY==aZ then aW=aW+1 else if aV~=nil then aX(aV,aW)end;aV=au;aW=1 end end)if aV~=nil then aX(aV,aW)end;if G[2]then local h,X=A(m(G[2]),table.concat(ae,"\n").."\n")if not h then print("uniq: "..G[2]..": "..tostring(X))end else for a0,T in ipairs(ae)do print(T)end end end;a6.tee=function(...)local F,G=B({...},"a")local a_=F.a and"a"or"w"local b0={}for a0,ag in ipairs(G)do local h,u=pcall(syscall.open,m(ag),a_)if not h then print("tee: "..ag..": "..tostring(u))else b0[#b0+1]=u end end;while true do local h,w=pcall(syscall.read,0,4096)if not h or not w or w==""then break end;pcall(syscall.write,1,w)for a0,u in ipairs(b0)do pcall(syscall.write,u,w)end end;for a0,u in ipairs(b0)do pcall(syscall.close,u)end end;a6.find=function(...)local ao={...}local b1,b2={},{}local b3,b4=nil,0;local k=1;while k<=#ao and ao[k]:sub(1,1)~="-"do b1[#b1+1]=ao[k]k=k+1 end;if#b1==0 then b1={"."}end;while k<=#ao do local b5=ao[k]if b5=="-name"then k=k+1;local aE="^"..(ao[k]or""):gsub("([%.%+%-%^%$%(%)%[%]%%])","%%%1"):gsub("%*",".*"):gsub("%?",".").."$"b2[#b2+1]=function(a0,a1,b6,b7)return a1:match(aE)~=nil end elseif b5=="-type"then k=k+1;local b8=ao[k]or""b2[#b2+1]=function(a0,a0,v,b6)if b8=="f"then return v=="file"elseif b8=="d"then return v=="directory"elseif b8=="l"then return v=="symlink"end;return true end elseif b5=="-maxdepth"then k=k+1;b3=tonumber(ao[k])or 0 elseif b5=="-mindepth"then k=k+1;b4=tonumber(ao[k])or 0 elseif b5=="-empty"then b2[#b2+1]=function(y,a0,v,b6)if v=="file"then local h,a3=pcall(syscall.stat,y)return h and a3 and(a3.size or 0)==0 elseif v=="directory"then local h,T=pcall(syscall.listdir,y)return h and T and#T==0 end;return false end end;k=k+1 end;local function b9(y,a1,v,ba)for a0,bb in ipairs(b2)do if not bb(y,a1,v,ba)then return false end end;return true end;local function bc(y,bd,ba)local v=syscall.type(y)if not v then return end;local a1=y:match("([^/]+)/?$")or y;if ba>=b4 and b9(y,a1,v,ba)then print(bd)end;if v=="directory"and(b3==nil or ba1 and n:sub(-1)=="/"do n=n:sub(1,-2)end;local ay=n:match("([^/]+)$")or n;if G[2]and ay:sub(-#G[2])==G[2]then ay=ay:sub(1,#ay-#G[2])end;print(ay)end;a6.dirname=function(...)local G={...}if#G==0 then print("dirname: missing operand")return end;for a0,n in ipairs(G)do while#n>1 and n:sub(-1)=="/"do n=n:sub(1,-2)end;local s=n:match("^(.*)/[^/]+$")if not s then print(".")elseif s==""then print("/")else print(s)end end end;a6.df=function(...)local F,a0=B({...},"h")local function bk(ac)local ah={"K","M","G","T"}local k=0;while ac>=1024 and k<#ah do ac=ac/1024;k=k+1 end;if k==0 then return tostring(math.floor(ac))end;if ac<10 then return string.format("%.1f%s",ac,ah[k])end;return math.floor(ac)..ah[k]end;local function az(ac)return F.h and bk(ac)or tostring(ac)end;print(string.format("%-20s %10s %10s %10s %6s %-s","Filesystem","Size","Used","Avail","Use%","Mounted on"))local bl={{"$","/"},{"devfs0000","/dev/"},{"tmpfs0000","/tmp/"}}for a0,aL in ipairs(bl)do local bm,bn=aL[1],aL[2]print(string.format("%-20s %10s %10s %10s %6s %-s",bm,"?","?","?","?%",bn))end end;local function bo(aO,aP)local h,bp=pcall(syscall.listdir,aO)if not h or not bp then return{}end;local aj={}for a0,a1 in ipairs(bp)do if aP==""or a1:sub(1,#aP)==aP then local bq=(aO=="/"and"/"or aO.."/")..a1;local v=syscall.type(bq)aj[#aj+1]=v=="directory"and a1 .."/"or a1 end end;table.sort(aj)return aj end;local function br(aP)local aj={}local bs={}for bt in pairs(a6)do if aP==""or bt:sub(1,#aP)==aP then if not bs[bt]then aj[#aj+1]=bt;bs[bt]=true end end end;local bu=string.split(syscall.getEnviron("PATH")or"/bin/",":")for a0,n in ipairs(bu)do local h,bp=pcall(syscall.listdir,n)if h and bp then for a0,a1 in ipairs(bp)do local bq=(n:sub(-1)=="/"and n or n.."/")..a1;local bv=pcall(syscall.access,bq,"x")if bv and(aP==""or a1:sub(1,#aP)==aP)then if not bs[a1]then aj[#aj+1]=a1;bs[a1]=true end end end end end;table.sort(aj)return aj end;local function bw(_)if#_==0 then return""end;local bx=_[1]for k=2,#_ do local a3=_[k]local I=1;while I<=#bx and I<=#a3 and bx:sub(I,I)==a3:sub(I,I)do I=I+1 end;bx=bx:sub(1,I-1)if bx==""then return""end end;return bx end;local function by(bz)syscall.write(1,"\n")local bA=51;local bB=0;for a0,L in ipairs(bz)do if#L>bB then bB=#L end end;local bC=bB+2;local bD=math.max(1,math.floor(bA/bC))local k=0;for a0,L in ipairs(bz)do local bE=L..string.rep(" ",bC-#L)syscall.write(1,bE)k=k+1;if k%bD==0 then syscall.write(1,"\n")end end;if k%bD~=0 then syscall.write(1,"\n")end end;local function bF(bG,bH)local bI=bG:sub(1,bH-1)local bJ={}for b5 in bI:gmatch("%S+")do bJ[#bJ+1]=b5 end;local bK=bI:match("%S+$")or""local bL=#bJ==0 or bI:sub(-1)~=" "and#bJ==1;local bM,bN;if bK:find("/")then bM=bK:match("^(.*/)")or"/"bN=bK:match("[^/]*$")or""else bM=nil;bN=bK end;return bJ,bK,bL,bM,bN end;local bO={last=nil,idx=0,list={}}local function bP(bG,bH)local bJ,bK,bL,bM,bN=bF(bG,bH)local bQ;if bL then if bM then local aO=bM:sub(1,1)=="/"and bM or syscall.getcwd().."/"..bM;bQ=bo(aO,bN)for k,L in ipairs(bQ)do bQ[k]=bM..L end else bQ=br(bN)end else local aO,bR;if bM then aO=bM:sub(1,1)=="/"and bM or syscall.getcwd().."/"..bM;bR=bN else aO=syscall.getcwd()bR=bN end;bQ=bo(aO,bR)if bM then for k,L in ipairs(bQ)do bQ[k]=bM..L end end end;if#bQ==0 then return bG,bH,false end;local bS=bG.."\0"..tostring(bH)if bO.last~=bS then bO.last=bS;bO.idx=0;bO.list=bQ end;if#bQ==1 then local bT=bQ[1]local bU=bG:sub(1,bH-1-#bK)local bV=bG:sub(bH)local bW=bU..bT..bV;local bX=#bU+#bT+1;bO.last=nil;return bW,bX,true end;local bx=bw(bQ)if#bx>#bK then local bU=bG:sub(1,bH-1-#bK)local bV=bG:sub(bH)local bW=bU..bx..bV;local bX=#bU+#bx+1;bO.last=bW.."\0"..tostring(bX)bO.list=bQ;return bW,bX,true else by(bQ)return bG,bH,true end end;local function bY()syscall.devctl(1,"sfgc",0x00FF00)syscall.write(1,d)syscall.devctl(1,"sfgc",0xFFFFFF)syscall.write(1,":")syscall.devctl(1,"sfgc",0x24FFFF)syscall.write(1,syscall.getcwd())syscall.devctl(1,"sfgc",0xFFFFFF)syscall.write(1,"$ ")local bZ=syscall.devctl(1,"gpos")local b_=tonumber(bZ:sub(1,bZ:find(";")-1))local c0=tonumber(bZ:sub(bZ:find(";")+1))local bG=""local c1=false;local bH=1;local c2=0;local c3=true;local function c4()if#bG==0 then return""end;local a0,bK,bL,bM,bN=bF(bG,bH)if bH~=#bG+1 then return""end;local bQ;if bL then if bM then local aO=bM:sub(1,1)=="/"and bM or syscall.getcwd().."/"..bM;bQ=bo(aO,bN)for k,L in ipairs(bQ)do bQ[k]=bM..L end else bQ=br(bN)end else local aO,bR;if bM then aO=bM:sub(1,1)=="/"and bM or syscall.getcwd().."/"..bM;bR=bN else aO=syscall.getcwd()bR=bN end;bQ=bo(aO,bR)if bM then for k,L in ipairs(bQ)do bQ[k]=bM..L end end end;if#bQ==0 then return""end;local bx=bw(bQ)if#bx>#bK then return bx:sub(#bK+1)end;return""end;local function c5()syscall.devctl(1,"spos",b_,c0)syscall.write(1,string.sub(bG,1,bH-1))if c1 then syscall.devctl(1,"sfgc",0x000000)syscall.devctl(1,"sbgc",0xFFFFFF)end;if bH>#bG then syscall.write(1," ")else syscall.write(1,string.sub(bG,bH,bH))end;syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"sbgc",0x000000)local bV=string.sub(bG,bH+1)syscall.write(1,bV)local c6=c4()if#c6>0 then syscall.devctl(1,"sfgc",0x6D00FF)syscall.write(1,c6)syscall.devctl(1,"sfgc",0xFFFFFF)syscall.write(1," ")else syscall.write(1," ")end end;while true do local c7=syscall.read(0)if c7 and c7~=""then if c7==""then if bH>1 then bH=bH-1;c3=true end elseif c7==""then if bH<=#bG then bH=bH+1;c3=true end elseif c7==""then if c2<#e then c2=c2+1;bG=e[#e-c2+1]bH=#bG+1;c3=true end elseif c7==""then if c2>1 then c2=c2-1;bG=e[#e-c2+1]bH=#bG+1;c3=true elseif c2==1 then c2=0;bG=""bH=1;c3=true end elseif c7==""then bH=1;c3=true elseif c7==""then bH=#bG+1;c3=true elseif c7=="[3~"then if bH<=#bG then bG=string.sub(bG,1,bH-1)..string.sub(bG,bH+1)c3=true end elseif c7=="\t"then local bW,bX,c8=bP(bG,bH)if c8 then bG=bW;bH=bX;local c9=syscall.devctl(1,"gpos")local ca=c9:find(";")local cb=tonumber(c9:sub(1,ca-1))local cc=tonumber(c9:sub(ca+1))if cb>1 then syscall.devctl(1,"spos",1,cc)local cd=syscall.devctl(1,"size")or"51;19"local aC=tonumber(cd:match("^(%d+)"))or 51;syscall.write(1,string.rep(" ",aC))syscall.devctl(1,"spos",1,cc)end;syscall.devctl(1,"sfgc",0x00FF00)syscall.write(1,d)syscall.devctl(1,"sfgc",0xFFFFFF)syscall.write(1,":")syscall.devctl(1,"sfgc",0x00FFFF)syscall.write(1,syscall.getcwd())syscall.devctl(1,"sfgc",0xFFFFFF)syscall.write(1,"$ ")c9=syscall.devctl(1,"gpos")ca=c9:find(";")b_=tonumber(c9:sub(1,ca-1))c0=tonumber(c9:sub(ca+1))c3=true end elseif c7=="\b"then if bH>1 then bG=string.sub(bG,1,bH-2)..string.sub(bG,bH)bH=bH-1;c3=true end elseif c7=="\n"then syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"sbgc",0x000000)syscall.devctl(1,"spos",b_,c0)syscall.write(1,bG.." \n")return bG elseif#c7==1 and c7:byte(1)>=32 and c7:byte(1)<127 then bG=string.sub(bG,1,bH-1)..c7 ..string.sub(bG,bH)bH=bH+1;c3=true end end;local ce=math.floor(syscall.getUptime()/500)%2==0;if ce~=c1 then c1=ce;c3=true end;if c3 then c5()c3=false end end end;local function cf(cg,ch)syscall.devctl(1,"sfgc",0xFF0000)local a3=tostring(ch)local au,ci=a3:match("%]:(%d+): (.+)$")if not au then au,ci=a3:match(":(%d+): (.+)$")end;if au then printInline(cg..": error on line "..au..": ")print(ci)else print(cg..": "..a3)end;syscall.devctl(1,"sfgc",0xFFFFFF)end;local function cj(ck)do local cl=load("return "..ck,"@equation","t",{})if cl then local h,cm=pcall(cl)if h and type(cm)=="number"then print(cm)return end end end;f=false;local G=string.split(ck," ")for k=#G,1,-1 do if G[k]==""then table.remove(G,k)end end;if#G==0 then return end;if a6[G[1]]then local h,X=pcall(a6[G[1]],table.unpack(G,2))if not h then cf(G[1],X)end;return end;local cn=""if string.find(G[1],"/")then local co=G[1]if co:sub(1,1)~="/"then co=syscall.getcwd().."/"..co end;if c.exists(co)then cn=co end else local bu=string.split(syscall.getEnviron("PATH"),":")for a0,n in pairs(bu)do if c.exists(n..G[1])then cn=n..G[1]break end end;if cn==""then local a7=syscall.getcwd()local co=a7 ..(a7:sub(-1)=="/"and""or"/")..G[1]if c.exists(co)then cn=co end end end;if cn==""then print(G[1]..": Command not found")return end;local cg=cn:match("([^/]+)$")or G[1]local bv,cp=pcall(syscall.access,cn,"x")if not bv then syscall.devctl(1,"sfgc",0xFF0000)print(cg..": Permission denied")syscall.devctl(1,"sfgc",0xFFFFFF)return end;local cq=syscall.spawn(function()syscall.open("/dev/tty/1","r")syscall.open("/dev/tty/1","w")syscall.open("/dev/null","w")syscall.exec(cn,{table.unpack(G,2)})end,cg)while true do local cr,ab=syscall.collect(cq)if cr then if ab then print("\nTask exited with code:\n"..tostring(ab))end;return end;if f then local a4=syscall.kill(cq)if a4 then syscall.devctl(1,"sbgc",16)syscall.devctl(1,"sfgc",0xFF0000)print("\nProgram Terminated.")syscall.devctl(1,"sfgc",0xFFFFFF)end;f=false;break end;sleep(0.05)end end;while true do local ck=bY()if ck~=""then if ck~=e[#e]then table.insert(e,ck)end;cj(ck)end end end,debug.traceback)if not a then syscall.log("Error running shell: "..b,"ERROR")syscall.devctl(1,"sfgc",0xFF0000)syscall.devctl(1,"sbgc",0x000000)print()print("Error running shell: ")print(b)end diff --git a/prod/hysh/bin/id b/prod/hysh/bin/id new file mode 100644 index 0000000..6016ae6 --- /dev/null +++ b/prod/hysh/bin/id @@ -0,0 +1 @@ +local a={...}local b;if a[1]then b=syscall.getuid(a[1])if not b then print("id: user '"..a[1].."' does not exist")syscall.exit(1)return end else b=syscall.getuid()end;local c=syscall.getpasswd(b)local d=c and c.username or tostring(b)local e=c and c.gid or b;print(string.format("uid=%d(%s) gid=%d(%s)",b,d,e,d)) diff --git a/prod/hysh/bin/ll b/prod/hysh/bin/ll new file mode 100644 index 0000000..5cefbfd --- /dev/null +++ b/prod/hysh/bin/ll @@ -0,0 +1,3 @@ +local args={...} +table.insert(args, "-lah") +syscall.exec("/bin/ls", args) \ No newline at end of file diff --git a/prod/hysh/bin/ln b/prod/hysh/bin/ln new file mode 100644 index 0000000..1e64e42 --- /dev/null +++ b/prod/hysh/bin/ln @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={s=false,f=false,help=false}local c={}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if b[f]==nil then print(a..": unrecognized option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true elseif e:sub(1,1)=="-"then for g=2,#e do local f=e:sub(g,g)if b[f]==nil then print(a..": invalid option '-"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;b[f]=true end else table.insert(c,e)end end;if b.help then print("Usage: "..a.." [OPTION]... TARGET LINK_NAME")print(" "..a.." [OPTION]... TARGET... DIRECTORY")print("Create links between files.")print("")print("Options:")print(" -s make symbolic links instead of hard links")print(" -f remove existing destination files")print(" --help display this help and exit")print("")print("With no -s, hard links are not supported (filesystem limitation).")print("Use -s for symbolic links.")return end;if#c<2 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;if not b.s then print(a..": hard links are not supported; use -s for symbolic links")syscall.exit(1)return end;local h=c[#c]local i=syscall.type(h)=="directory"local function j()local k=syscall.getcwd()if k:sub(-1)~="/"then k=k.."/"end;return k end;local function l(m)if m:sub(1,1)~="/"then m=j()..m end;return m end;for g=1,#c-1 do local n=c[g]local o;if i then local p=n:match("[^/]+$")or n;o=l(h)if o:sub(-1)~="/"then o=o.."/"end;o=o..p else o=l(h)end;if b.f and syscall.exists(o)then local q,r=pcall(syscall.remove,o)if not q then print(a..": cannot remove '"..o.."': "..tostring(r))syscall.exit(1)return end end;local q,r=pcall(syscall.symlink,n,o)if not q then print(a..": failed to create symlink '"..o.."' -> '"..n.."': "..tostring(r))syscall.exit(1)return end end diff --git a/prod/hysh/bin/login b/prod/hysh/bin/login new file mode 100644 index 0000000..cdcb3b1 --- /dev/null +++ b/prod/hysh/bin/login @@ -0,0 +1 @@ +syscall.open("/dev/tty/1","r")syscall.open("/dev/tty/1","w")syscall.open("/dev/null","w")local a=3;local function b(c)local d=""while true do local e=syscall.read(0)if not e or e==""then elseif e=="\n"then syscall.write(1,"\n")return d elseif e=="\b"then if#d>0 then d=d:sub(1,-2)syscall.write(1,"\b \b")end else d=d..e;syscall.write(1,c or e)end end end;local function f()local g=""local h,i=pcall(function()local j=syscall.open("/etc/shadow","r")g=syscall.read(j,65535)or""syscall.close(j)end)if g:match("%S")then return end;syscall.devctl(1,"clear")syscall.devctl(1,"spos",1,1)syscall.devctl(1,"sfgc",0x00FF00)syscall.write(1,"HyperionOS First Boot Setup\n")syscall.devctl(1,"sfgc",0xFFFFFF)syscall.write(1,"No root password is set. Please create one now.\n\n")while true do syscall.write(1,"New root password: ")local k=b("*")syscall.write(1,"Confirm password: ")local l=b("*")if k~=l then syscall.devctl(1,"sfgc",0xFF0000)syscall.write(1,"Passwords do not match. Try again.\n\n")syscall.devctl(1,"sfgc",0xFFFFFF)elseif#k<6 then syscall.devctl(1,"sfgc",0xFF0000)syscall.write(1,"Password too short (minimum 6 characters).\n\n")syscall.devctl(1,"sfgc",0xFFFFFF)else local m,n=syscall.setpassword(0,k)if m then syscall.devctl(1,"sfgc",0x00FF00)syscall.write(1,"Root password set.\n\n")syscall.devctl(1,"sfgc",0xFFFFFF)sleep(0.5)break else syscall.devctl(1,"sfgc",0xFF0000)syscall.write(1,"Error: "..tostring(n).."\n")syscall.devctl(1,"sfgc",0xFFFFFF)end end end end;local function o(p,q,r,s)local t,u=pcall(syscall.exists,r)if not t or not u then syscall.write(1,"login: shell not found: "..r.."\n")sleep(2)return false end;local v,w=pcall(syscall.access,r,"rx")syscall.setEnviron("HOME",s)syscall.setEnviron("USER",p)syscall.setEnviron("SHELL",r)syscall.setEnviron("PATH","/bin/")local x,y=pcall(syscall.setuid,q)if not x then syscall.write(1,"login: setuid failed: "..tostring(y).."\n")sleep(2)return false end;local z,A=pcall(syscall.chdir,s)if not z then pcall(syscall.chdir,"/")end;local m,n=pcall(syscall.execspawn,r,p..":shell")if not m then syscall.write(1,"login: failed to launch shell: "..tostring(n).."\n")sleep(2)return false end;syscall.exit(0)end;local function B()syscall.devctl(1,"clear")syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"sbgc",0x000000)syscall.devctl(1,"spos",1,1)local C=syscall.getHostname()or"hyperion"syscall.write(1,"HyperionOS\n")syscall.write(1,C.." login\n\n")local D=0;while D ")print(" "..a.." -x ")print("")print("Pack a directory into a portable HFS image file, or extract one.")print("")print(" recursively pack srcdir into image.hfs")print(" -x extract image.hfs into dest (created if needed)")print("")print("HFS images can be mounted with:")print(" mount -o loop /path/to/image.hfs /mnt/point")print("")print("Requires root.")return end;local i=require("fs")if c.x then if#b<2 then print(a..": -x requires and ")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local j=b[1]local k=b[2]if j:sub(1,1)~="/"then j=syscall.getcwd().."/"..j end;if k:sub(1,1)~="/"then k=syscall.getcwd().."/"..k end;local l="/tmp/._loimgcreate_"..tostring(math.random(100000,999999))local m,n=pcall(syscall.losetup,j,true)if not m then print(a..": losetup: "..tostring(n))syscall.exit(1)return end;local o,p=pcall(syscall.mount,l,n)if not o then pcall(syscall.lodetach,n)print(a..": mount: "..tostring(p))syscall.exit(1)return end;if not i.isDir(k)then local q,r=pcall(syscall.mkdir,k)if not q then pcall(syscall.umount,l)pcall(syscall.lodetach,n)print(a..": mkdir '"..b[2].."': "..tostring(r))syscall.exit(1)return end end;local s=0;local function t(u,v)local w=i.list(u)if not w then return end;for d,x in ipairs(w)do local y=u:gsub("/$","").."/"..x;local z=v:gsub("/$","").."/"..x;if i.isDir(y)then pcall(syscall.mkdir,z)t(y,z)else local A,B=pcall(syscall.open,y,"r")if A then local o,C=pcall(syscall.open,z,"w")if o then local q,D=pcall(syscall.read,B,65536*16)if q and D then pcall(syscall.write,C,D)end;pcall(syscall.close,C)s=s+1 end;pcall(syscall.close,B)end end end end;t(l,k)pcall(syscall.umount,l)pcall(syscall.lodetach,n)syscall.devctl(1,"sfgc",0x00FFFF)print(a..": extracted "..s.." file(s) to "..k)syscall.devctl(1,"sfgc",0xFFFFFF)return end;if#b<2 then print(a..": missing operands — need and ")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local E=b[1]local j=b[2]if E:sub(1,1)~="/"then E=syscall.getcwd().."/"..E end;if j:sub(1,1)~="/"then j=syscall.getcwd().."/"..j end;if not i.isDir(E)then print(a..": '"..b[1].."': not a directory")syscall.exit(1)return end;local A,F=pcall(syscall.loimgcreate,E)if not A then local G=tostring(F)if G:find("EPERM")then G="Permission denied"elseif G:find("ENOTDIR")then G="'"..b[1].."': not a directory"end;print(a..": "..G)syscall.exit(1)return end;local o,H=pcall(syscall.loimgwrite,F,j)if not o then print(a..": write '"..b[2].."': "..tostring(H))syscall.exit(1)return end;local I=0;for d in F:gmatch("\n")do I=I+1 end;local J=#F;syscall.devctl(1,"sfgc",0x00FFFF)print(a..": image written to "..j)syscall.devctl(1,"sfgc",0x6D00FF)print(string.format(" %d records, %d bytes",I-1,J))syscall.devctl(1,"sfgc",0xFFFFFF) diff --git a/prod/hysh/bin/losetup b/prod/hysh/bin/losetup new file mode 100644 index 0000000..393988c --- /dev/null +++ b/prod/hysh/bin/losetup @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b,c={},{d=false,l=false,i=false,help=false}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if f=="help"then c.help=true else print(a..": unrecognised option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end elseif e:sub(1,1)=="-"then for g=2,#e do local h=e:sub(g,g)if c[h]~=nil then c[h]=true else print(a..": invalid option '-"..h.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end end else table.insert(b,e)end end;if c.help then print("Usage: "..a.." ")print(" "..a.." -i ")print(" "..a.." -d ")print(" "..a.." -l")print("")print("Manage loop devices.")print("")print(" attach a directory (bind) or .hfs image file")print(" -i force image mode for the given file")print(" -d detach loop device by id (must be unmounted first)")print(" -l list all currently attached loop devices")print("")print("Requires root. Loop device ids look like loop0, loop1, …")return end;if c.l then local i,j=pcall(syscall.lolist)if not i then print(a..": "..tostring(j))syscall.exit(1)return end;local k=false;local l={}for m in pairs(j)do l[#l+1]=m end;table.sort(l)for d,m in ipairs(l)do k=true;local n=j[m]local o=type(n)=="table"and n.mode or"bind"local p=type(n)=="table"and n.path or tostring(n)local q=o=="image"and 0x00FFFF or 0x0000FF;syscall.devctl(1,"sfgc",0x00FF00)printInline(string.format("%-10s",m))syscall.devctl(1,"sfgc",q)printInline(string.format("%-7s","["..o.."]"))syscall.devctl(1,"sfgc",0xFFFFFF)print(" "..p)end;if not k then syscall.devctl(1,"sfgc",0x6D00FF)print(a..": no loop devices attached")syscall.devctl(1,"sfgc",0xFFFFFF)end;return end;if c.d then if#b<1 then print(a..": -d requires a loop device id")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local m=b[1]local i,r=pcall(syscall.lodetach,m)if not i then local s=tostring(r)if s:find("EPERM")then s="Permission denied"elseif s:find("ENXIO")then s="no such loop device '"..m.."'"elseif s:find("EBUSY")then s="device '"..m.."' is still mounted, unmount first"end;print(a..": "..s)syscall.exit(1)return end;syscall.devctl(1,"sfgc",0x00FFFF)print(a..": detached "..m)syscall.devctl(1,"sfgc",0xFFFFFF)return end;if#b<1 then print(a..": missing path operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local p=b[1]if p:sub(1,1)~="/"then p=syscall.getcwd().."/"..p end;local t=syscall.type and syscall.type(p)if not(t=="file"or t=="directory")then print(a..": '"..b[1].."': no such file or directory")syscall.exit(1)return end;local i,u=pcall(syscall.losetup,p,c.i or nil)if not i then local s=tostring(u)if s:find("EPERM")then s="Permission denied"elseif s:find("ENOENT")then s="'"..b[1].."': no such file"elseif s:find("EINVAL")then s="'"..b[1].."': not a directory or .hfs image"elseif s:find("EIO")then s="'"..b[1].."': I/O error reading image"end;print(a..": "..s)syscall.exit(1)return end;print(u) diff --git a/prod/hysh/bin/ls b/prod/hysh/bin/ls new file mode 100644 index 0000000..1972c42 --- /dev/null +++ b/prod/hysh/bin/ls @@ -0,0 +1 @@ +local a={a=false,h=false,l=false,help=false}local b={...}local c={}local d=syscall.getTask(syscall.getpid()).name;for e,f in pairs(b)do if f:sub(1,2)=="--"then local g=f:sub(3)if a[g]==nil then print(d..": unrecognized option '"..f.."'.")print("try '"..d.." --help' for more information.")return end;a[g]=true elseif f:sub(1,1)=="-"then for h=2,#f do local g=f:sub(h,h)if a[g]==nil then print(d..": invalid option '-"..g.."'.")print("try '"..d.." --help' for more information.")return end;a[g]=true end else table.insert(c,f)end end;if a.help then print("Usage: "..d.." [OPTION]... [DIR]")print("List all entries in the specified DIRectory, or cwd if not specified.")print("")print("Options:")print(" -a do not ignore entries starting with .")print(" -h with -l, print sizes in human readable format")print(" -l use a long listing format")print(" --help display this help and exit")return end;local i=require("fs")local j=c[1]or""if j:sub(1,1)~="/"then j=syscall.getcwd().."/"..j end;if j:sub(-1)~="/"then j=j.."/"end;if not i.isDir(j)then print(d..": cannot access '"..(c[1]or j).."': no such directory")return end;local function k(l,m)local function n(o)return math.floor(l/2^o)%2==1 end;local p;if m==0x01 then p="l"elseif m==nil then p="-"else p="-"end;local q=n(5)and"r"or"-"local r=n(4)and"w"or"-"local s=n(9)and(n(6)and"s"or"x")or(n(6)and"S"or"-")local t=n(3)and"r"or"-"local u=n(2)and"w"or"-"local v=n(8)and"x"or"-"local w=n(1)and"r"or"-"local x=n(0)and"w"or"-"local y=n(7)and"x"or"-"return p..q..r..s..t..u..v..w..x..y end;local z={"K","M","G","T"}local function A(B)local C=0;while B>=1024 and C<#z do B=B/1024;C=C+1 end;if C==0 then return tostring(B).."B"end;if B<10 then return string.format("%.1f%s",B,z[C])end;return math.floor(B)..z[C]end;local D=syscall.devctl(1,"size")local E=tonumber(D:match("^(%d+)"))or 80;local F=i.list(j)if not a.a then for h=#F,1,-1 do if F[h]:sub(1,1)=="."then table.remove(F,h)end end end;table.sort(F)if#F==0 then return end;if a.l then for e,f in ipairs(F)do local G=j..f;local H=syscall.lstat and syscall.lstat(G)or syscall.stat(G)local I=i.isDir(G)local J=H and H.etype==0x01;local isSock=H and H.etype==0x02;local K;if J then K="l"elseif I then K="d"elseif isSock then K="s"else K="-"end;local L;if H and H.perms then L=k(H.perms,H.etype)else L=K.."---------"end;local B=H and H.size or 0;local M=a.h and A(B)or tostring(B)local N=H and H.modified and math.floor(H.modified/1000)or 0;local O=H and tostring(H.owner)or"0"local P=H and tostring(H.group)or"0"printInline(L.." "..O.." "..P.." ")printInline(string.format("%6s",M).." ")printInline(tostring(N).." ")if J then syscall.devctl(1,"sfgc",0x00FFFF)printInline(f)syscall.devctl(1,"sfgc",0xFFFFFF)local Q,R=pcall(syscall.readlink,G)if Q then printInline(" -> ")local S=pcall(syscall.stat,G)syscall.devctl(1,"sfgc",S and 0x00FFFF or 0xFF0000)printInline(R)syscall.devctl(1,"sfgc",0xFFFFFF)end elseif I then syscall.devctl(1,"sfgc",0x6D00FF)printInline(f)syscall.devctl(1,"sfgc",0xFFFFFF)elseif isSock then syscall.devctl(1,"sfgc",0xFF00FF)printInline(f)syscall.devctl(1,"sfgc",0xFFFFFF)else local T=H and H.perms and math.floor(H.perms/2^9)%2==1;syscall.devctl(1,"sfgc",T and 0x00FF00 or 0xFFFFFF)printInline(f)syscall.devctl(1,"sfgc",0xFFFFFF)end;print("")end;return end;local U=0;for e,f in ipairs(F)do if#f+2>U then U=#f+2 end end;local V=math.max(1,math.floor(E/U))for h,f in ipairs(F)do local G=j..f;local I=i.isDir(G)local H=syscall.lstat and syscall.lstat(G)or syscall.stat(G)local J=H and H.etype==0x01;if J then syscall.devctl(1,"sfgc",0x00FFFF)elseif I then syscall.devctl(1,"sfgc",0x6D00FF)elseif isSock then syscall.devctl(1,"sfgc",0xFF00FF)else local T=H and H.perms and math.floor(H.perms/2^9)%2==1;syscall.devctl(1,"sfgc",T and 0x00FF00 or 0xFFFFFF)end;printInline(f)syscall.devctl(1,"sfgc",0xFFFFFF)printInline((" "):rep(U-#f))if h%V==0 then print("")end end;if#F%V~=0 then print("")end diff --git a/prod/hysh/bin/lsusers b/prod/hysh/bin/lsusers new file mode 100644 index 0000000..6a5fa28 --- /dev/null +++ b/prod/hysh/bin/lsusers @@ -0,0 +1 @@ +local a=syscall.listusers()if not a or#a==0 then print("No users found.")return end;syscall.devctl(1,"sfgc",0xDBDBDB)print(string.format("%-6s %-6s %-16s %-20s %s","UID","GID","Username","Home","Shell"))print(string.rep("-",65))syscall.devctl(1,"sfgc",0xFFFFFF)for b,c in ipairs(a)do local d=c.locked and" [locked]"or""if c.locked then syscall.devctl(1,"sfgc",0xFF0000)end;print(string.format("%-6d %-6d %-16s %-20s %s%s",c.uid,c.gid,c.username,c.homedir,c.shell,d))if c.locked then syscall.devctl(1,"sfgc",0xFFFFFF)end end diff --git a/prod/hysh/bin/mount b/prod/hysh/bin/mount new file mode 100644 index 0000000..d73e0f0 --- /dev/null +++ b/prod/hysh/bin/mount @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b,c={},{help=false,o=nil}local d=1;local e={...}while d<=#e do local f=e[d]if f:sub(1,2)=="--"then local g=f:sub(3)if g=="help"then c.help=true else print(a..": unrecognised option '"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end elseif f=="-o"then d=d+1;c.o=e[d]elseif f:sub(1,1)=="-"then local h=f:sub(2)if h:sub(1,1)=="o"then if#h>1 then c.o=h:sub(2)else d=d+1;c.o=e[d]end else print(a..": invalid option '"..f.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end else table.insert(b,f)end;d=d+1 end;if c.help then print("Usage: "..a)print(" "..a.." ")print(" "..a.." -o loop ")print("")print("Mount a loop device or filesystem.")print("")print(" (no args) list all active mount points")print(" mount an already-attached loop device")print(" -o loop attach src as loop device and mount at dest")print(" src can be a directory (bind) or .hfs image")print("")print("Requires root for all operations except listing.")return end;if#b==0 and not c.o then local i,j=pcall(syscall.mounts or function()error("ENOSYS")end)local k={}local l,m=pcall(syscall.lolist)if l then for n,o in pairs(m)do local p=type(o)=="table"and o.path or tostring(o)local q=type(o)=="table"and o.mode or"bind"k[n]={path=p,mode=q}end end;if next(k)==nil then syscall.devctl(1,"sfgc",0xFF00FF)print("(no loop devices attached)")syscall.devctl(1,"sfgc",0xFFFFFF)return end;for n,o in pairs(k)do local r=o.mode=="image"and 0x00FFFF or 0x0000FF;syscall.devctl(1,"sfgc",r)printInline(o.mode.." "..n)syscall.devctl(1,"sfgc",0xFFFFFF)print(" on "..o.path)end;return end;if c.o and c.o:lower()=="loop"then if#b<2 then print(a..": -o loop requires and ")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local s=b[1]local t=b[2]if s:sub(1,1)~="/"then s=syscall.getcwd().."/"..s end;if t:sub(1,1)~="/"then t=syscall.getcwd().."/"..t end;local i,u=pcall(syscall.losetup,s)if not i then local v=tostring(u)if v:find("EPERM")then v="Permission denied"elseif v:find("EINVAL")then v="'"..b[1].."': not a directory or .hfs image"elseif v:find("EIO")then v="'"..b[1].."': I/O error reading image"end;print(a..": losetup: "..v)syscall.exit(1)return end;local w,x=pcall(syscall.mount,t,u)if not w then pcall(syscall.lodetach,u)local v=tostring(x)if v:find("EPERM")then v="Permission denied"elseif v:find("EBUSY")then v="'"..t.."' is already a mount point"elseif v:find("ENODEV")then v="loop device not found (internal error)"end;print(a..": mount: "..v)syscall.exit(1)return end;syscall.devctl(1,"sfgc",0x00FFFF)print(a..": "..u.." mounted at "..t)syscall.devctl(1,"sfgc",0xFFFFFF)return end;if#b==2 then local u=b[1]local t=b[2]if t:sub(1,1)~="/"then t=syscall.getcwd().."/"..t end;local i,y=pcall(syscall.mount,t,u)if not i then local v=tostring(y)if v:find("EPERM")then v="Permission denied"elseif v:find("ENODEV")then v="'"..u.."': no such device - use losetup first"elseif v:find("EBUSY")then v="'"..t.."' is already a mount point"elseif v:find("EINVAL")then v="invalid arguments"end;print(a..": "..v)syscall.exit(1)return end;syscall.devctl(1,"sfgc",0x00FFFF)print(a..": "..u.." mounted at "..t)syscall.devctl(1,"sfgc",0xFFFFFF)return end;print(a..": wrong number of arguments")print("try '"..a.." --help' for more information.")syscall.exit(1) diff --git a/prod/hysh/bin/passwd b/prod/hysh/bin/passwd new file mode 100644 index 0000000..f7b3e2b --- /dev/null +++ b/prod/hysh/bin/passwd @@ -0,0 +1 @@ +local a={...}local b=a[1]local c=syscall.getuid()local d;if b then d=syscall.getuid()if not d then print("passwd: user '"..b.."' does not exist")syscall.exit(1)return end;if c~=0 and d~=c then print("passwd: permission denied")syscall.exit(1)return end else d=c;b=syscall.getUsername(c)or tostring(c)end;if c~=0 then printInline("Current password: ")local e=""while true do local f=syscall.read(0)if not f or f==""then elseif f=="\n"then syscall.write(1,"\n")break elseif f=="\b"then if#e>0 then e=e:sub(1,-2)syscall.write(1,"\b \b")end else e=e..f;syscall.write(1,"*")end end;local g,h=syscall.login(d,e)if not g then sleep(1)print("passwd: authentication failure")syscall.exit(1)return end end;printInline("New password: ")local i=""while true do local f=syscall.read(0)if not f or f==""then elseif f=="\n"then syscall.write(1,"\n")break elseif f=="\b"then if#i>0 then i=i:sub(1,-2)syscall.write(1,"\b \b")end else i=i..f;syscall.write(1,"*")end end;printInline("Confirm password: ")local j=""while true do local f=syscall.read(0)if not f or f==""then elseif f=="\n"then syscall.write(1,"\n")break elseif f=="\b"then if#j>0 then j=j:sub(1,-2)syscall.write(1,"\b \b")end else j=j..f;syscall.write(1,"*")end end;if i~=j then print("passwd: passwords do not match")syscall.exit(1)return end;local g,h=syscall.setpassword(d,i)if not g then print("passwd: "..tostring(h))syscall.exit(1)return end;print("passwd: password updated for '"..b.."'") diff --git a/prod/hysh/bin/ps b/prod/hysh/bin/ps new file mode 100644 index 0000000..11d9cc3 --- /dev/null +++ b/prod/hysh/bin/ps @@ -0,0 +1 @@ +for a,b in ipairs(syscall.getTasks())do local c=syscall.getTask(b)print(c.pid,c.username,c.name,c.status)end diff --git a/prod/hysh/bin/readlink b/prod/hysh/bin/readlink new file mode 100644 index 0000000..52522cc --- /dev/null +++ b/prod/hysh/bin/readlink @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={n=false,f=false,e=false,help=false}local c={}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if b[f]==nil then print(a..": unrecognized option '"..e.."'")syscall.exit(1)return end;b[f]=true elseif e:sub(1,1)=="-"then for g=2,#e do local f=e:sub(g,g)if b[f]==nil then print(a..": invalid option '-"..f.."'")syscall.exit(1)return end;b[f]=true end else table.insert(c,e)end end;if b.help then print("Usage: "..a.." [OPTION]... FILE...")print("Print the resolved target of symbolic links.")print("")print("Options:")print(" -f canonicalize: follow every symlink; last component need not exist")print(" -e like -f but all components must exist")print(" -n do not output trailing newline")print(" --help display this help and exit")return end;if#c==0 then print(a..": missing operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local function h(i)if i:sub(1,1)~="/"then local j=syscall.getcwd()if j:sub(-1)~="/"then j=j.."/"end;i=j..i end;return i end;local k=false;for d,l in ipairs(c)do l=h(l)if b.f or b.e then local m,n=pcall(syscall.stat,l)if not m then if b.e then print(a..": "..l..": "..tostring(n))k=true else if not b.n then print(l)else printInline(l)end end else if not b.n then print(l)else printInline(l)end end else local m,o=pcall(syscall.readlink,l)if not m then print(a..": "..l..": "..tostring(o))k=true else if not b.n then print(o)else printInline(o)end end end end;if k then syscall.exit(1)end diff --git a/prod/hysh/bin/su b/prod/hysh/bin/su new file mode 100644 index 0000000..3f4e394 --- /dev/null +++ b/prod/hysh/bin/su @@ -0,0 +1 @@ +local a=({...})[1]local b=syscall.getuid()if syscall.geteuid()~=0 then syscall.exec("/bin/su",{...})end;local c;if a then c=syscall.getuidbyname(a)else c=0 end;if not c then print("su: user '"..a.."' does not exist")syscall.exit(1)return end;if b~=0 then printInline("Password: ")local d=""while true do local e=syscall.read(0)if not e or e==""then elseif e=="\n"then syscall.write(1,"\n")break elseif e=="\b"then if#d>0 then d=d:sub(1,-2)syscall.write(1,"\b \b")end else d=d..e;syscall.write(1,"*")end end;local f,g=syscall.login(c,d)if not f then sleep(1)print("su: Authentication failure")syscall.exit(1)return end else syscall.setuid(c)end;local h=syscall.getpasswd(c)local i=h and h.shell or"/bin/hysh"local j=h and h.homedir or"/"local k=h and h.username or"Unknown"local l,m=pcall(syscall.chdir,j)if not l then j="/"syscall.chdir(j)end;syscall.setEnviron("HOME",j)syscall.setEnviron("USER",k)syscall.setEnviron("SHELL",i)local f,g=pcall(syscall.exec,i)if not f then print("su: cannot exec shell '"..i.."': "..tostring(g))syscall.exit(1)end diff --git a/prod/hysh/bin/sudo b/prod/hysh/bin/sudo new file mode 100644 index 0000000..e2f59d0 --- /dev/null +++ b/prod/hysh/bin/sudo @@ -0,0 +1 @@ +local a=require("fs")local b={...}local c="root"local d=1;if b[d]=="-u"then d=d+1;local e=b[d]or"root"local f=tonumber(e)if f then local g=syscall.getpasswd(f)c=g and g.username or e else c=e end;d=d+1 end;local h=b[d]if not h or h==""then print("usage: sudo [-u user] [args...]")syscall.exit(1)return end;local i={}for j=d+1,#b do i[#i+1]=b[j]end;local k=syscall.getuid()local l=syscall.getUsername(k)or tostring(k)local m=syscall.getuidbyname(c)if not m then print("sudo: user '"..c.."' does not exist")syscall.exit(1)return end;if k~=0 then printInline("[sudo] password for root: ")local n=""while true do local o=syscall.read(0)if not o or o==""then elseif o=="\n"then syscall.write(1,"\n")break elseif o=="\b"then if#n>0 then n=n:sub(1,-2)syscall.write(1,"\b \b")end else n=n..o;syscall.write(1,"*")end end;local p,q=syscall.login(0,n)if not p then sleep(1)print("sudo: Authentication failure")syscall.exit(1)return end;if m~=k then syscall.setuid(m)end else if m~=k then syscall.setuid(m)end end;local r=""if h:find("/")then if a.exists(h)then r=h end else local s=string.split(syscall.getEnviron("PATH")or"/bin/",":")for t,u in ipairs(s)do local v=u..h;if a.exists(v)then r=v;break end end end;if r==""then print("sudo: command not found: "..h)syscall.exit(1)return end;local w=a.readAllText(r)local x,y=load(w,"@"..r)if not x then print("sudo: cannot load "..h..": "..tostring(y))syscall.exit(1)return end;local g=syscall.getpasswd(m)if g and g.homedir then syscall.setEnviron("HOME",g.homedir)end;syscall.setEnviron("USER",c)local p,q=xpcall(x,debug.traceback,table.unpack(i))if not p then print("sudo: "..h..": "..tostring(q))syscall.exit(1)end diff --git a/prod/hysh/bin/sysdump b/prod/hysh/bin/sysdump new file mode 100644 index 0000000..0c87cb2 --- /dev/null +++ b/prod/hysh/bin/sysdump @@ -0,0 +1 @@ +local a=...a=a or"/dev/tty/1"local b=syscall.sysdump()local c=syscall.open(a,"w")for d=1,#b do syscall.write(c,b[d].."\n")end;syscall.write(c,"Total # of syscalls: "..tostring(#b))syscall.close(c) diff --git a/prod/hysh/bin/umount b/prod/hysh/bin/umount new file mode 100644 index 0000000..a0f9c15 --- /dev/null +++ b/prod/hysh/bin/umount @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b,c={},{l=false,["no-detach"]=false,help=false}for d,e in ipairs({...})do if e:sub(1,2)=="--"then local f=e:sub(3)if c[f]~=nil then c[f]=true else print(a..": unrecognised option '"..e.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end elseif e:sub(1,1)=="-"then for g=2,#e do local h=e:sub(g,g)if c[h]~=nil then c[h]=true else print(a..": invalid option '-"..h.."'")print("try '"..a.." --help' for more information.")syscall.exit(1)return end end else table.insert(b,e)end end;if c.help then print("Usage: "..a.." ")print(" "..a.." --no-detach ")print(" "..a.." -l ")print("")print("Unmount a filesystem mounted at .")print("")print(" unmount and auto-detach any loop device")print(" --no-detach unmount but keep the loop device attached")print(" -l forcibly detach a loop device (no unmount)")print("")print("Requires root.")return end;if c.l then if#b<1 then print(a..": -l requires a loop device id")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local i=b[1]local j,k=pcall(syscall.lodetach,i)if not j then local l=tostring(k)if l:find("EPERM")then l="Permission denied"elseif l:find("ENXIO")then l="no such loop device '"..i.."'"elseif l:find("EBUSY")then l="'"..i.."' is still mounted - unmount first or omit -l"end;print(a..": "..l)syscall.exit(1)return end;syscall.devctl(1,"sfgc",0x00FFFF)print(a..": detached "..i)syscall.devctl(1,"sfgc",0xFFFFFF)return end;if#b<1 then print(a..": missing mount point operand")print("try '"..a.." --help' for more information.")syscall.exit(1)return end;local m=b[1]if m:sub(1,1)~="/"then m=syscall.getcwd().."/"..m end;local n=nil;if not c["no-detach"]then local o,p=pcall(syscall.lolist)if o then n={}for i in pairs(p)do n[#n+1]=i end end end;local j,k=pcall(syscall.umount,m)if not j then local l=tostring(k)if l:find("EPERM")then l="Permission denied"elseif l:find("EINVAL")then l="'"..b[1].."' is not a mount point"elseif l:find("EBUSY")then l="'"..b[1].."' is busy - close open files first"end;print(a..": "..l)syscall.exit(1)return end;syscall.devctl(1,"sfgc",0x00FFFF)print(a..": unmounted "..m)syscall.devctl(1,"sfgc",0xFFFFFF)if n then for d,i in ipairs(n)do local q=pcall(syscall.lodetach,i)if q then syscall.devctl(1,"sfgc",0xFF00FF)print(a..": auto-detached "..i)syscall.devctl(1,"sfgc",0xFFFFFF)end end end diff --git a/prod/hysh/bin/useradd b/prod/hysh/bin/useradd new file mode 100644 index 0000000..e08f46d --- /dev/null +++ b/prod/hysh/bin/useradd @@ -0,0 +1 @@ +local a={...}local b=1;local c={createHome=true}while b<=#a do local d=a[b]if d=="-p"then b=b+1;c.password=a[b]elseif d=="-g"then b=b+1;c.gid=tonumber(a[b])elseif d=="-d"then b=b+1;c.homedir=a[b]elseif d=="-s"then b=b+1;c.shell=a[b]elseif d=="-M"then c.createHome=false elseif d:sub(1,1)~="-"then c.username=d else print("useradd: unknown option: "..d)return end;b=b+1 end;if not c.username then print("Usage: useradd [-p password] [-g gid] [-d homedir] [-s shell] [-M] ")syscall.exit(1)return end;local e=c.password;if not e then printInline("New password: ")e=""while true do local f=syscall.read(0)if not f or f==""then elseif f=="\n"then syscall.write(1,"\n")break elseif f=="\b"then if#e>0 then e=e:sub(1,-2)syscall.write(1,"\b \b")end else e=e..f;syscall.write(1,"*")end end;printInline("Confirm password: ")local g=""while true do local f=syscall.read(0)if not f or f==""then elseif f=="\n"then syscall.write(1,"\n")break elseif f=="\b"then if#g>0 then g=g:sub(1,-2)syscall.write(1,"\b \b")end else g=g..f;syscall.write(1,"*")end end;if e~=g then print("useradd: passwords do not match")syscall.exit(1)return end end;local h,i=syscall.newuser(c.username,e,c.gid,c.homedir,c.shell or"/bin/hysh")if not h then print("useradd: "..tostring(i))syscall.exit(1)return end;if c.createHome then local j=c.homedir or"/home/"..c.username;local k,l=pcall(syscall.mkdir,j)if not k then print("useradd: warning: could not create home "..j..": "..tostring(l))end end;print("useradd: created user '"..c.username.."' with uid="..tostring(h)) diff --git a/prod/hysh/bin/userdel b/prod/hysh/bin/userdel new file mode 100644 index 0000000..9c6c9e1 --- /dev/null +++ b/prod/hysh/bin/userdel @@ -0,0 +1 @@ +local a={...}local b=false;local c=nil;for d,e in ipairs(a)do if e=="-r"then b=true elseif e:sub(1,1)~="-"then c=e else print("userdel: unknown option: "..e)syscall.exit(1)return end end;if not c then print("Usage: userdel [-r] ")syscall.exit(1)return end;local f=syscall.getuid(c)if not f then print("userdel: user '"..c.."' does not exist")syscall.exit(1)return end;local g=syscall.getpasswd(f)local h,i=syscall.deleteuser(f)if not h then print("userdel: "..tostring(i))syscall.exit(1)return end;if b and g and g.homedir then local j=require("fs")local k,l=pcall(function()local function m(n)for d,o in ipairs(j.list(n)or{})do local p=n.."/"..o;if j.isDir(p)then m(p)else syscall.remove(p)end end;syscall.remove(n)end;if j.exists(g.homedir)then m(g.homedir)end end)if not k then print("userdel: warning: could not remove home: "..tostring(l))end end;print("userdel: deleted user '"..c.."'") diff --git a/prod/hysh/bin/usermod b/prod/hysh/bin/usermod new file mode 100644 index 0000000..294e83a --- /dev/null +++ b/prod/hysh/bin/usermod @@ -0,0 +1 @@ +local a={...}local b=1;local c={}while b<=#a do local d=a[b]if d=="-l"then b=b+1;c.newname=a[b]elseif d=="-p"then b=b+1;c.password=a[b]elseif d=="-g"then b=b+1;c.gid=tonumber(a[b])elseif d=="-d"then b=b+1;c.homedir=a[b]elseif d=="-s"then b=b+1;c.shell=a[b]elseif d=="-L"then c.lock=true elseif d=="-U"then c.unlock=true elseif d:sub(1,1)~="-"then c.username=d else print("usermod: unknown option: "..d)syscall.exit(1)return end;b=b+1 end;if not c.username then print("Usage: usermod [-l newname] [-p password] [-g gid] [-d homedir] [-s shell] [-L] [-U] ")syscall.exit(1)return end;if c.lock and c.unlock then print("usermod: -L and -U are mutually exclusive")syscall.exit(1)return end;local e=syscall.getuid(c.username)if not e then print("usermod: user '"..c.username.."' does not exist")syscall.exit(1)return end;local function f(g,...)local h,i=g(...)if not h then print("usermod: "..tostring(i))syscall.exit(1)end end;if c.newname then f(syscall.setusername,e,c.newname)end;if c.password then f(syscall.setpassword,e,c.password)end;if c.gid then f(syscall.setgid,e,c.gid)end;if c.homedir then f(syscall.sethomedir,e,c.homedir)end;if c.shell then f(syscall.setshell,e,c.shell)end;if c.lock then f(syscall.lockuser,e)end;if c.unlock then f(syscall.unlockuser,e)end;print("usermod: updated user '"..c.username.."'") diff --git a/prod/hysh/bin/yes b/prod/hysh/bin/yes new file mode 100644 index 0000000..f9b868d --- /dev/null +++ b/prod/hysh/bin/yes @@ -0,0 +1 @@ +local a={...}while true do if#a==0 then print("y")else print(table.concat(a," "))end end diff --git a/prod/iniparse/lib/iniparse b/prod/iniparse/lib/iniparse new file mode 100644 index 0000000..3578307 --- /dev/null +++ b/prod/iniparse/lib/iniparse @@ -0,0 +1 @@ +local a={}function a.parse(b)local c={}local d=nil;for e in b:gmatch("[^\r\n]+")do e=e:match("^%s*(.-)%s*$")if e~=""and not e:match("^[;#]")then local f=e:match("^%[(.-)%]$")if f then d=f;c[d]=c[d]or{}else local g,h=e:match("^(.-)=(.*)$")if g then g=g:match("^%s*(.-)%s*$")h=h:match("^%s*(.-)%s*$")if d then c[d][g]=h else c[g]=h end end end end end;return c end;return a diff --git a/prod/json/lib/json b/prod/json/lib/json new file mode 100644 index 0000000..f3e5b56 --- /dev/null +++ b/prod/json/lib/json @@ -0,0 +1 @@ +local a={_version="0.1.2"}local b;local c={["\\"]="\\",["\""]="\"",["\b"]="b",["\f"]="f",["\n"]="n",["\r"]="r",["\t"]="t"}local d={["/"]="/"}for e,f in pairs(c)do d[f]=e end;local function g(h)return"\\"..(c[h]or string.format("u%04x",h:byte()))end;local function i(j)return"null"end;local function k(j,l)local m={}l=l or{}if l[j]then error("circular reference")end;l[j]=true;if rawget(j,1)~=nil or next(j)==nil then local n=0;for e in pairs(j)do if type(e)~="number"then error("invalid table: mixed or invalid key types")end;n=n+1 end;if n~=#j then error("invalid table: sparse array")end;for o,f in ipairs(j)do table.insert(m,b(f,l))end;l[j]=nil;return"["..table.concat(m,",").."]"else for e,f in pairs(j)do if type(e)~="string"then error("invalid table: mixed or invalid key types")end;table.insert(m,b(e,l)..":"..b(f,l))end;l[j]=nil;return"{"..table.concat(m,",").."}"end end;local function p(j)return'"'..j:gsub('[%z\1-\31\\"]',g)..'"'end;local function q(j)if j~=j or j<=-math.huge or j>=math.huge then error("unexpected number value '"..tostring(j).."'")end;return string.format("%.14g",j)end;local r={["nil"]=i,["table"]=k,["string"]=p,["number"]=q,["boolean"]=tostring}b=function(j,l)local s=type(j)local t=r[s]if t then return t(j,l)end;error("unexpected type '"..s.."'")end;function a.encode(j)return b(j)end;local u;local function v(...)local m={}for o=1,select("#",...)do m[select(o,...)]=true end;return m end;local w=v(" ","\t","\r","\n")local x=v(" ","\t","\r","\n","]","}",",")local y=v("\\","/",'"',"b","f","n","r","t","u")local z=v("true","false","null")local A={["true"]=true,["false"]=false,["null"]=nil}local function B(C,D,E,F)for o=D,#C do if E[C:sub(o,o)]~=F then return o end end;return#C+1 end;local function G(C,D,H)local I=1;local J=1;for o=1,D-1 do J=J+1;if C:sub(o,o)=="\n"then I=I+1;J=1 end end;error(string.format("%s at line %d col %d",H,I,J))end;local function K(n)local t=math.floor;if n<=0x7f then return string.char(n)elseif n<=0x7ff then return string.char(t(n/64)+192,n%64+128)elseif n<=0xffff then return string.char(t(n/4096)+224,t(n%4096/64)+128,n%64+128)elseif n<=0x10ffff then return string.char(t(n/262144)+240,t(n%262144/4096)+128,t(n%4096/64)+128,n%64+128)end;error(string.format("invalid unicode codepoint '%x'",n))end;local function L(M)local N=tonumber(M:sub(1,4),16)local O=tonumber(M:sub(7,10),16)if O then return K((N-0xd800)*0x400+O-0xdc00+0x10000)else return K(N)end end;local function P(C,o)local m=""local Q=o+1;local e=Q;while Q<=#C do local R=C:byte(Q)if R<32 then G(C,Q,"control character in string")elseif R==92 then m=m..C:sub(e,Q-1)Q=Q+1;local h=C:sub(Q,Q)if h=="u"then local S=C:match("^[dD][89aAbB]%x%x\\u%x%x%x%x",Q+1)or C:match("^%x%x%x%x",Q+1)or G(C,Q-1,"invalid unicode escape in string")m=m..L(S)Q=Q+#S else if not y[h]then G(C,Q-1,"invalid escape char '"..h.."' in string")end;m=m..d[h]end;e=Q+1 elseif R==34 then m=m..C:sub(e,Q-1)return m,Q+1 end;Q=Q+1 end;G(C,o,"expected closing quote for string")end;local function T(C,o)local R=B(C,o,x)local M=C:sub(o,R-1)local n=tonumber(M)if not n then G(C,o,"invalid number '"..M.."'")end;return n,R end;local function U(C,o)local R=B(C,o,x)local V=C:sub(o,R-1)if not z[V]then G(C,o,"invalid literal '"..V.."'")end;return A[V],R end;local function W(C,o)local m={}local n=1;o=o+1;while 1 do local R;o=B(C,o,w,true)if C:sub(o,o)=="]"then o=o+1;break end;R,o=u(C,o)m[n]=R;n=n+1;o=B(C,o,w,true)local X=C:sub(o,o)o=o+1;if X=="]"then break end;if X~=","then G(C,o,"expected ']' or ','")end end;return m,o end;local function Y(C,o)local m={}o=o+1;while 1 do local Z,j;o=B(C,o,w,true)if C:sub(o,o)=="}"then o=o+1;break end;if C:sub(o,o)~='"'then G(C,o,"expected string for key")end;Z,o=u(C,o)o=B(C,o,w,true)if C:sub(o,o)~=":"then G(C,o,"expected ':' after key")end;o=B(C,o+1,w,true)j,o=u(C,o)m[Z]=j;o=B(C,o,w,true)local X=C:sub(o,o)o=o+1;if X=="}"then break end;if X~=","then G(C,o,"expected '}' or ','")end end;return m,o end;local _={['"']=P,["0"]=T,["1"]=T,["2"]=T,["3"]=T,["4"]=T,["5"]=T,["6"]=T,["7"]=T,["8"]=T,["9"]=T,["-"]=T,["t"]=U,["f"]=U,["n"]=U,["["]=W,["{"]=Y}u=function(C,D)local X=C:sub(D,D)local t=_[X]if t then return t(C,D)end;G(C,D,"unexpected character '"..X.."'")end;function a.decode(C)if type(C)~="string"then error("expected argument of type string, got "..type(C))end;local m,D=u(C,B(C,1,w,true))D=B(C,D,w,true)if D<=#C then G(C,D,"trailing garbage")end;return m end;return a diff --git a/prod/lua/bin/lua b/prod/lua/bin/lua new file mode 100644 index 0000000..fcfe302 --- /dev/null +++ b/prod/lua/bin/lua @@ -0,0 +1 @@ +local a=0xFFFF00;local b=0xDBDBDB;local c=0x00FFFF;local d=0xFF0000;local e=0x00FF00;local f=0x00FF88;local g=0x24FFFF;local h=0xFF6D00;local i=0x6D6D6D;local j=0xDBDBDB;local function k(l)syscall.devctl(1,"sfgc",l)end;local function m(n)syscall.write(1,tostring(n))end;local o=6;local p=64;local function q(r,s,t)s=s or 0;t=t or{}local u=type(r)if u=="nil"then k(i)m("nil")elseif u=="boolean"then k(h)m(tostring(r))elseif u=="number"then k(g)if r~=r then m("nan")elseif r==math.huge then m("inf")elseif r==-math.huge then m("-inf")elseif r==math.floor(r)and math.abs(r)<1e15 then m(tostring(math.floor(r)))else m(tostring(r))end elseif u=="string"then k(f)local n=string.format("%q",r)m(n)elseif u=="function"then k(j)m(tostring(r))elseif u=="table"then if t[r]then k(j)m("")return end;if s>=o then k(j)m("")return end;t[r]=true;local v=string.rep(" ",s)local w=string.rep(" ",s+1)local x={}local y={}local z=#r;for A in pairs(r)do if type(A)=="number"and A>=1 and A<=z and A==math.floor(A)then x[#x+1]=A else y[#y+1]=A end end;table.sort(x)table.sort(y,function(B,C)local D,E=type(B),type(C)if D==E then if D=="string"then return Bp then return true end;m(w)if type(A)=="number"and x[A]then else if type(A)=="string"and A:match("^[a-zA-Z_][a-zA-Z0-9_]*$")then k(e)m(A)else k(j)m("[")q(A,s+1,t)k(j)m("]")end;k(j)m(" = ")end;q(I,s+1,t)k(j)if not J then m(",")end;m("\n")end;for K,A in ipairs(x)do m(w)q(r[A],s+1,t)k(j)if K=p then k(i)m(w.."-- ..."..F-G.." more entries\n")break end end;if G

=F;m(w)if type(A)=="string"and A:match("^[a-zA-Z_][a-zA-Z0-9_]*$")then k(e)m(A)else k(j)m("[")q(A,s+1,t)k(j)m("]")end;k(j)m(" = ")q(r[A],s+1,t)k(j)G=G+1;if G=p then local L=F-G;if L>0 then k(i)m(w.."-- ..."..L.." more entries\n")end;break end end end;k(j)m(v.."}")t[r]=nil else k(j)m(tostring(r))end;k(1)end;local function M(...)local N=select("#",...)if N==0 then return end;for K=1,N do if K>1 then k(j)m("\t")end;q(select(K,...),0,{})end;m("\n")k(1)end;local O=setmetatable({},{__index=_ENV})O._G=O;O.print=function(...)local N=select("#",...)for K=1,N do if K>1 then m("\t")end;q(select(K,...),0,{})end;m("\n")k(1)end;O.pp=function(r)q(r,0,{})m("\n")k(1)end;O.exit=setmetatable({},{__tostring=function()return"function: exit()"end,__call=function()syscall.exit()end})local function P(Q)local R=load("return "..Q,"@lua","t",O)if R then return R,true end;local S,T=load(Q,"@lua","t",O)return S,false,T end;local function U(Q)local V,T=load(Q,"@lua","t",O)return T and(T:find("")~=nil or T:find("'end'")~=nil or T:find("'then'")~=nil or T:find("'until'")~=nil)end;local function W(X)return tostring(X):gsub("^%[string .-%]:",""):gsub("^@lua:",""):gsub("stack traceback:.*",""):match("^%s*(.-)%s*$")end;local function Y(Q)local Z,_,T=P(Q)if not Z then k(d)m("[error] ")k(1)m(W(T).."\n")return end;local a0=table.pack(xpcall(Z,debug.traceback))local a1=table.remove(a0,1)a0.n=a0.n-1;if not a1 then k(d)m("[error] ")k(1)m(W(a0[1]).."\n")elseif _ and a0.n>0 then k(c)m("= ")M(table.unpack(a0,1,a0.n))end end;local function a2(a3,a4)k(a)m(a3)k(1)local a5=syscall.devctl(1,"gpos")local a6=tonumber(a5:sub(1,a5:find(";")-1))local a7=tonumber(a5:sub(a5:find(";")+1))local a8=""local a9=1;local aa=0;local ab=false;local ac=true;local function ad()syscall.devctl(1,"spos",a6,a7)m(a8:sub(1,a9-1))if ab then syscall.devctl(1,"sfgc",0x000000)syscall.devctl(1,"sbgc",1)end;m(a9>#a8 and" "or a8:sub(a9,a9))syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"sbgc",16)m(a8:sub(a9+1).." ")ac=false end;while true do local ae=syscall.read(0)if ae and ae~=""then if ae==""then if a9>1 then a9=a9-1;ac=true end elseif ae==""then if a9<=#a8 then a9=a9+1;ac=true end elseif ae==""then if a4 and aa<#a4 then aa=aa+1;a8=a4[#a4-aa+1]a9=#a8+1;ac=true end elseif ae==""then if aa>1 then aa=aa-1;a8=a4[#a4-aa+1]a9=#a8+1;ac=true elseif aa==1 then aa=0;a8=""a9=1;ac=true end elseif ae=="\b"then if a9>1 then a8=a8:sub(1,a9-2)..a8:sub(a9)a9=a9-1;ac=true end elseif ae=="\n"then syscall.devctl(1,"sfgc",0xFFFFFF)syscall.devctl(1,"sbgc",16)syscall.devctl(1,"spos",a6,a7)m(a8 .." \n")return a8 elseif#ae==1 and ae:byte(1)>=32 and ae:byte(1)<127 then a8=string.sub(a8,1,a9-1)..ae..string.sub(a8,a9)a9=a9+1;ac=true end end;local af=math.floor(syscall.getUptime()/500)%2==0;if af~=ab then ab=af;ac=true end;if ac then ad()end end end;k(a)m("HyperionOS ".._VERSION.."\n")k(i)m("Interactive Lua REPL. exit() to quit.\n\n")k(1)local a4={}while true do local Q=a2("lua> ",a4)if Q~=""then while U(Q)do Q=Q.."\n"..a2("... ",nil)end;if Q~=a4[#a4]then a4[#a4+1]=Q end;Y(Q)end end diff --git a/prod/micro/bin/micro b/prod/micro/bin/micro new file mode 100644 index 0000000..1bae4dc --- /dev/null +++ b/prod/micro/bin/micro @@ -0,0 +1 @@ +local a={...}local function b()local c=syscall.devctl(1,"size")return tonumber(c:match("^(%d+)"))or 80,tonumber(c:match(";(%d+)$"))or 24 end;local function d(e,f)syscall.devctl(1,"spos",e,f)end;local function g(h)syscall.devctl(1,"sfgc",h)end;local function i(h)syscall.devctl(1,"sbgc",h)end;local function j(c)if c and c~=""then syscall.write(1,c)end end;local function k()syscall.devctl(1,"clear")end;local l,m=b()local n=m-2;local o={""}local p=1;local q=1;local r=0;local s=true;local t=nil;local u=""local v=false;local w=nil;local x=""local y=0;local z=false;local function A(B)if B:sub(1,1)=="/"then return B end;local C=syscall.getcwd()C=C:gsub("/+$","")return C.."/"..B end;local function D(E)if not syscall.exists(E)then o={""}u="[new file]"return end;local F=syscall.open(E,"r")local G=""while true do local h=syscall.read(F,4096)if not h or h==""then break end;G=G..h end;syscall.close(F)o={}for H in(G.."\n"):gmatch("([^\n]*)\n")do table.insert(o,H)end;if#o>1 and o[#o]==""and G:sub(-1)=="\n"then table.remove(o)end;if#o==0 then o={""}end end;local function I(E)local J,K=pcall(function()local F=syscall.open(E,"w")for L,H in ipairs(o)do syscall.write(F,H)if L<#o then syscall.write(F,"\n")end end;syscall.write(F,"\n")syscall.close(F)end)if J then u="Saved: "..E;v=false else u="Save failed: "..tostring(K)v=true end end;local function M(N)return math.max(1,math.ceil(#N/l))end;local function O(P,Q)return math.floor((Q-1)/l)end;local function R()local S={}local T=0;for P=1,#o do local U=#o[P]local V=M(o[P])for W=0,V-1 do T=T+1;S[T]={P,W*l+1}end end;return S,T end;local function X(S)local Y=O(q,p)for T,Z in ipairs(S)do if Z[1]==q and math.floor((Z[2]-1)/l)==Y then return T end end;return 1 end;local function _()local a0=#o[q]+1;if p>a0 then p=a0 end;if p<1 then p=1 end end;local function a1(S)local a2=X(S)if a2-1=r+n then r=a2-n end;if r<0 then r=0 end end;local function a3(c,a4)if#c>=a4 then return c:sub(1,a4)end;return c..string.rep(" ",a4-#c)end;local function a5()d(1,1)i(0x0000FF)g(0x000000)local a6=" edit"..(t and" - "..t or"")if s then a6=a6 .." [+]"end;local a7=tostring(q)..","..tostring(p).." "j(a3(a6 ..string.rep(" ",math.max(1,l-#a6-#a7))..a7,l))i(0x000000)g(0xFFFFFF)end;local function a8()d(1,m)i(0x0000FF)g(0x000000)if u~=""then if v then i(2)end;j(a3(" "..u,l))u=""v=false else j(a3(" ^W Save ^X Quit+Save ^P Quit ^K Cut ^U Paste ^F Find ^G Go",l))end;i(0x000000)g(0xFFFFFF)end;local function a9(S)local aa=X(S)local ab=O(q,p)local ac=p-ab*l;for ad=1,n do local T=r+ad;d(1,ad+1)local Z=S[T]if Z then local P=Z[1]local ae=Z[2]local af=o[P]:sub(ae,ae+l-1)local ag=T==aa;if ag then local ah=ac;ah=math.min(ah,#af+1)local ai=af:sub(1,ah-1)local aj=ah>#af and" "or af:sub(ah,ah)local ak=af:sub(ah+1)g(0xFFFFFF)i(0x000000)j(ai)if z then g(0x000000)i(0xFFFFFF)else g(0xFFFFFF)i(0x000000)end;j(aj)g(0xFFFFFF)i(0x000000)j(ak)local al=#ai+1+#ak;if al0 then ar=ar:sub(1,-2)end else local at=as:byte(1)if at>=32 and at<127 then ar=ar..as:sub(1,1)end end end end;local function au(h)local H=o[q]o[q]=H:sub(1,p-1)..h..H:sub(p)p=p+1;s=true end;local function av()if p>1 then local H=o[q]o[q]=H:sub(1,p-2)..H:sub(p)p=p-1;s=true elseif q>1 then local aw=o[q-1]p=#aw+1;o[q-1]=aw..o[q]table.remove(o,q)q=q-1;s=true end end;local function ax()local H=o[q]if p<=#H then o[q]=H:sub(1,p-1)..H:sub(p+1)s=true elseif q<#o then o[q]=H..o[q+1]table.remove(o,q+1)s=true end end;local function ay()local H=o[q]local az=H:sub(1,p-1)local aA=H:sub(p)local aB=az:match("^(%s*)")or""o[q]=az;table.insert(o,q+1,aB..aA)q=q+1;p=#aB+1;s=true end;local function aC()w=o[q]table.remove(o,q)if#o==0 then o={""}end;if q>#o then q=#o end;p=1;s=true;u="Cut"end;local function aD()if not w then u="Nothing to paste"return end;table.insert(o,q,w)q=q+1;p=1;s=true;u="Pasted"end;local function aE()if x==""then local B=ao("Find: ","")if not B or B==""then s=true;return end;x=B;y=0 end;local aF=y>0 and y or q;for L=1,#o do local aG=(aF-1+L)%#o+1;if o[aG]:find(x)then q=aG;y=aG;p=o[aG]:find(x)or 1;u="Found: line "..aG;s=true;return end end;u="Not found: "..x;v=true;s=true end;local function aH()local B=ao("Go to line: ","")if not B then s=true;return end;local aI=tonumber(B)if not aI then u="Not a number"v=true;s=true;return end;q=math.max(1,math.min(#o,math.floor(aI)))p=1;u="Line "..q;s=true end;local function aJ()if not t then local B=ao("Save as: ","")s=true;if not B or B==""then return false end;t=A(B)end;I(t)s=true;return not v end;local function aK(S)local a2=X(S)if a2<=1 then return end;local aL=S[a2-1]if not aL then return end;local aM=aL[1]local aN=aL[2]+(p-1)%l;p=math.min(aN,#o[aM]+1)q=aM end;local function aO(S)local a2=X(S)local aP=S[a2+1]if not aP then return end;local aM=aP[1]local aN=aP[2]+(p-1)%l;p=math.min(aN,#o[aM]+1)q=aM end;if a[1]then t=A(a[1])D(t)end;k()local aQ=true;while aQ do local S=R()local as=syscall.read(0)if as and as~=""then local at=as:byte(1)if as==""then aK(S)s=true elseif as==""then aO(S)s=true elseif as==""then if p<=#o[q]then p=p+1 elseif q<#o then q=q+1;p=1 end;s=true elseif as==""then if p>1 then p=p-1 elseif q>1 then q=q-1;p=#o[q]+1 end;s=true elseif as==""then p=1;s=true elseif as==""then p=#o[q]+1;s=true elseif as=="[5~"then for aR=1,n do aK(S)end;s=true elseif as=="[6~"then for aR=1,n do aO(S)end;s=true elseif as=="[3~"then ax()elseif as=="\n"then ay()elseif as=="\b"then av()elseif as=="\t"then for aR=1,4 do au(" ")end elseif at==6 then local B=ao("Find: ",x)s=true;if B then x=B;y=0;aE()end elseif at==7 then aH()elseif at==11 then aC()elseif at==14 then if x==""then local B=ao("Find: ","")s=true;if B then x=B;y=0 end end;aE()elseif at==16 then if s then local B=ao("Unsaved changes. Quit? [y/N] ","")s=true;if B and B:lower()=="y"then aQ=false end else aQ=false end elseif at==21 then aD()elseif at==23 then aJ()elseif at==24 then aJ()aQ=false else if at>=32 and at<127 then au(as:sub(1,1))end end end;local aS=math.floor(syscall.getUptime()/500)%2==0;if aS~=z then z=aS;s=true end;if s then _()an()s=false end end;k()g(0xFFFFFF)i(0x000000)d(1,1)print("edit: exited"..(t and" - "..t or"")) diff --git a/prod/sed/bin/sed b/prod/sed/bin/sed new file mode 100644 index 0000000..9362053 --- /dev/null +++ b/prod/sed/bin/sed @@ -0,0 +1 @@ +local a=syscall.getTask(syscall.getpid()).name;local b={}local c={}local d=false;local e=false;local f={...}local g=1;while g<=#f do local h=f[g]if h=="-n"then d=true elseif h=="-i"then e=true elseif h=="-e"then g=g+1;if not f[g]then print(a..": option -e requires an argument")syscall.exit(1)return end;table.insert(b,f[g])elseif h:sub(1,2)=="-e"then table.insert(b,h:sub(3))elseif h=="--help"then print("Usage: "..a.." [OPTION]... SCRIPT [FILE...]")print(" "..a.." [OPTION]... -e SCRIPT... [FILE...]")print("Stream editor. Reads FILE(s) (or stdin) line by line,")print("applies SCRIPT, and writes results to stdout.")print("")print("Commands:")print(" s/REGEX/REPL/[flags] substitute (flags: g global, i ignore-case, p print)")print(" d delete line (skip to next)")print(" p print current line")print(" q quit")print(" = print current line number")print(" y/src/dst/ transliterate characters")print("")print("Addressing (prefix any command):")print(" N line number N")print(" $ last line")print(" /REGEX/ lines matching regex")print(" N,M line range")print(" N,/REGEX/ from line N until regex match")print("")print("Options:")print(" -n suppress default output")print(" -e SCRIPT add script expression")print(" -i edit file in-place")print(" --help display this help and exit")return elseif h:sub(1,1)=="-"then print(a..": unknown option: "..h)syscall.exit(1)return else if#b==0 then table.insert(b,h)else table.insert(c,h)end end;g=g+1 end;if#b==0 then print(a..": no script specified")syscall.exit(1)return end;local i=table.concat(b,"\n")local function j(k)return k:gsub("([%(%)%.%%%+%-%*%?%[%^%$])","%%%1")end;local function l(m,n)m=m:gsub("\\%(","("):gsub("\\%)",")")m=m:gsub("\\1","%%1"):gsub("\\2","%%2")return m end;local function o(k,p,q)local r={}while p<=#k do local s=k:sub(p,p)if s=="\\"and p<#k then p=p+1;local t=k:sub(p,p)if t==q then table.insert(r,q)elseif t=="n"then table.insert(r,"\n")else table.insert(r,"\\"..t)end elseif s==q then return table.concat(r),p+1 else table.insert(r,s)end;p=p+1 end;return table.concat(r),p end;local function u(k,p)local s=k:sub(p,p)if s==""then return nil,p end;if s:match("%d")then local v=k:match("^(%d+)",p)return{type="line",n=tonumber(v)},p+#v elseif s=="$"then return{type="last"},p+1 elseif s=="/"then local m,w=o(k,p+1,"/")return{type="regex",pat=m},w end;return nil,p end;local function x(y)local z={}local p=1;local A=#y;local function B()while p<=A and(y:sub(p,p)==" "or y:sub(p,p)=="\t")do p=p+1 end end;while p<=A do B()if p>A then break end;local s=y:sub(p,p)if s=="\n"or s==";"then p=p+1 elseif s=="#"then while p<=A and y:sub(p,p)~="\n"do p=p+1 end else local C,D;C,p=u(y,p)B()if C and p<=A and y:sub(p,p)==","then p=p+1;B()D,p=u(y,p)end;B()if p>A then break end;local E=y:sub(p,p)p=p+1;if E=="s"then local q=y:sub(p,p)p=p+1;local m,F=o(y,p,q)p=F;local G,H=o(y,p,q)p=H;local I=""while p<=A and y:sub(p,p):match("[giIp]")do I=I..y:sub(p,p)p=p+1 end;table.insert(z,{addr1=C,addr2=D,cmd="s",pat=m,repl=G,flags=I})elseif E=="y"then local q=y:sub(p,p)p=p+1;local J,F=o(y,p,q)p=F;local K,H=o(y,p,q)p=H;table.insert(z,{addr1=C,addr2=D,cmd="y",src=J,dst=K})elseif E=="d"or E=="p"or E=="q"or E=="="then table.insert(z,{addr1=C,addr2=D,cmd=E})elseif E=="{"then local L=1;local M=p;while p<=A and L>0 do local N=y:sub(p,p)if N=="{"then L=L+1 elseif N=="}"then L=L-1 end;p=p+1 end;local O=y:sub(M,p-2)local P=x(O)for Q,R in ipairs(P)do R.addr1=R.addr1 or C;R.addr2=R.addr2 or D end;for Q,R in ipairs(P)do table.insert(z,R)end elseif E=="\n"or E==";"then else end end end;return z end;local z=x(i)local S={}local function T(E,U,V,W,X)local Y=E.addr1;local Z=E.addr2;if not Y then return true end;local function _(a0,a1,a2)if a0.type=="line"then return a1==a0.n elseif a0.type=="last"then return W elseif a0.type=="regex"then return a2:find(l(a0.pat))~=nil end;return false end;if not Z then return _(Y,U,V)end;if S[X]then local a3;if Z.type=="line"then a3=U>=Z.n elseif Z.type=="last"then a3=W elseif Z.type=="regex"then a3=V:find(l(Z.pat))~=nil end;if a3 then S[X]=false end;return true else if _(Y,U,V)then if Z.type=="line"and Z.n<=U then else S[X]=true end;return true end;return false end end;local function a4(V,m,G,I)local a5=I:find("g")~=nil;local n=I:find("[iI]")~=nil;local a6=l(m,n)local function a7(a8,...)local a9={...}local r={}local aa=G;local ab=1;while ab<=#aa do local ac=aa:sub(ab,ab)if ac=="&"then table.insert(r,a8)elseif ac=="\\"and ab<#aa then ab=ab+1;local t=aa:sub(ab,ab)if t:match("%d")then local ad=tonumber(t)table.insert(r,a9[ad]or"")elseif t=="n"then table.insert(r,"\n")else table.insert(r,t)end else table.insert(r,ac)end;ab=ab+1 end;return table.concat(r)end;local ae;local af=false;if a5 then ae=V:gsub(a6,a7)af=ae~=V else local k,ag,a8;local ah={V:find(a6)}if ah[1]then k=ah[1]ag=ah[2]local a9={}for X=3,#ah do a9[#a9+1]=ah[X]end;local ai=V:sub(k,ag)local aj=a7(ai,table.unpack(a9))ae=V:sub(1,k-1)..aj..V:sub(ag+1)af=true else ae=V end end;return ae,af end;local function ak(V,y,al)local r={}for X=1,#V do local s=V:sub(X,X)local ad=y:find(s,1,true)if ad and ad<=#al then table.insert(r,al:sub(ad,ad))else table.insert(r,s)end end;return table.concat(r)end;local function am(an,ao)local ap=#an;for U,V in ipairs(an)do local W=U==ap;local aq=false;local ar=false;local as=false;local at=V:gsub("\n$","")for X,E in ipairs(z)do if T(E,U,at,W,X)then if E.cmd=="d"then aq=true;break elseif E.cmd=="p"then table.insert(ao,at)elseif E.cmd=="="then table.insert(ao,tostring(U))elseif E.cmd=="q"then if not d then table.insert(ao,at)end;as=true;break elseif E.cmd=="s"then local au,af=a4(at,E.pat,E.repl,E.flags)at=au;if af and E.flags:find("p")then table.insert(ao,at)end elseif E.cmd=="y"then at=ak(at,E.src,E.dst)end end end;if as then break end;if not aq and not d then table.insert(ao,at)end end end;local function av(aw)local an={}local ax=""while true do local ay=syscall.read(aw,1024)if not ay or ay==""then break end;ax=ax..ay end;for V in(ax.."\n"):gmatch("([^\n]*)\n")do table.insert(an,V)end;if ax~=""and ax:sub(-1)~="\n"and an[#an]==""then table.remove(an)end;return an end;local function az(aA)local aw;if aA then local aB,aC=pcall(function()aw=syscall.open(aA,"r")end)if not aB then print(a..": "..aA..": "..tostring(aC))return false end else aw=0 end;local an=av(aw)if aA then syscall.close(aw)end;S={}local ao={}am(an,ao)if e and aA then local aD=syscall.open(aA,"w")for Q,aE in ipairs(ao)do syscall.write(aD,aE.."\n")end;syscall.close(aD)else for Q,aE in ipairs(ao)do print(aE)end end;return true end;if#c==0 then az(nil)else for Q,aF in ipairs(c)do local aG=aF;if aG:sub(1,1)~="/"then aG=syscall.getcwd().."/"..aF end;az(aG)end end diff --git a/prod/spm/bin/spm b/prod/spm/bin/spm new file mode 100644 index 0000000..9756ac9 --- /dev/null +++ b/prod/spm/bin/spm @@ -0,0 +1,6 @@ +local args={...} + +local json=require("json") +local http=require("http") +local rootRepo="https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm/spm.src" + diff --git a/prod/sysinit/sbin/init b/prod/sysinit/sbin/init new file mode 100644 index 0000000..5071168 --- /dev/null +++ b/prod/sysinit/sbin/init @@ -0,0 +1,4 @@ +local args={...} +syscall.remove("/sbin/init") +syscall.symlink("/usr/lib/sysinit/sysinit", "/sbin/init") +syscall.exec("/sbin/init", args) \ No newline at end of file diff --git a/prod/sysinit/usr/lib/sysinit/sysinit b/prod/sysinit/usr/lib/sysinit/sysinit new file mode 100644 index 0000000..0d16d30 --- /dev/null +++ b/prod/sysinit/usr/lib/sysinit/sysinit @@ -0,0 +1 @@ +local a=...local b=require("fs")a.log("Sysinit started...")for c,d in pairs(a.processes)do a.log("Spawning kernel task "..c)syscall.spawn(function()local e,f=pcall(d)if not e then a.log("Error executing kernel task '"..c.."': "..f,"ERROR",0xFF0000)else a.log("Successfully executed kernel task: "..c)end end,c)end;if not b.exists("/bin/startup")then b.mkdir("/bin/startup")end;local g=b.list("/bin/startup")if not g then error("Failed to list /bin/startup")end;for c,d in ipairs(g)do if d:sub(-4)==".lua"then local h="/bin/startup/"..d;a.log("Executing startup script: "..h)local i,f=load(b.readAllText(h),"@"..h)if not i then a.log("Error loading startup script '"..h.."': "..f,"ERROR",0xFF0000)else syscall.spawn(function()syscall.setuid(1)local e,f=pcall(i)if not e then a.log("Error executing startup script '"..h.."': "..f,"ERROR",0xFF0000)else a.log("Successfully executed startup script: "..h)end end,"startup:"..d)end end end;while true do sleep(5)a.saveLog()end