From 0072547beb0afaabf56c2582f9f6fe6b79833f1c Mon Sep 17 00:00:00 2001 From: Astronand Date: Sat, 21 Mar 2026 00:59:46 -0400 Subject: [PATCH] updated package list --- Src/install.json | 7 ++++++- prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod | 2 +- prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod | 2 +- .../lib/modules/hyperion/45_hypervisor.kmod | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Src/install.json b/Src/install.json index 3f83663..101d46d 100644 --- a/Src/install.json +++ b/Src/install.json @@ -1,3 +1,8 @@ [ - "" + "Hyperion-kernel", + "Hyperion-core", + "hysh", + "lua", + "micro", + "sysinit" ] \ No newline at end of file diff --git a/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod index 568a93e..45719ac 100644 --- a/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod +++ b/prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod @@ -1 +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") +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)if a.unixSockets[aI(G)]then return true end;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/20_socket.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod index 7d41d37..74ab5ee 100644 --- a/prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod +++ b/prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod @@ -1 +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") +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 g then error("ECCON")end;return f.read()end,write=function()if 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/45_hypervisor.kmod b/prod/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod index 852a690..f5338e3 100644 --- a/prod/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod +++ b/prod/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod @@ -1 +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 +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 if not F.debugger then N={e(F.coro,F.timeSlice,table.unpack(F.syscallReturn))}else N={coroutine.resume(F.coro,table.unpack(F.syscallReturn))}end 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