hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-10-11 02:16:56 +0200
committerhachem <im@hachem.wtf>2026-10-11 02:16:56 +0200
commit59794d0b999e544a94230d9562bf2b99d2ed74c7 (patch)
treea001db5b5ebb9453d6a0e96f56b36e6ec3ccdd51
parent88750ed7132c08bcfb24e878c893ef7185c3c0b0 (diff)
feat: actual real vfs, not a faked one lmao
-rw-r--r--bridge/bridge.zig2
-rw-r--r--bridge/hosts.zig30
-rw-r--r--build.zig5
-rw-r--r--etc/lung79
-rw-r--r--etc/motd1
-rw-r--r--etc/profile8
-rw-r--r--gils/cat.rv3
-rw-r--r--gils/cp.rv6
-rw-r--r--gils/ed.rv8
-rw-r--r--gils/head.rv4
-rw-r--r--gils/ls.rv11
-rw-r--r--gils/mkdir.rv2
-rw-r--r--gils/mv.rv8
-rw-r--r--gils/rm.rv2
-rw-r--r--gils/tail.rv4
-rw-r--r--gils/touch.rv6
-rw-r--r--gils/tree.rv12
-rw-r--r--gils/wc.rv4
-rw-r--r--kernel/io.rv12
-rw-r--r--kernel/seed.rv13
-rw-r--r--kernel/shell.rv4
-rw-r--r--kernel/vfs.rv345
22 files changed, 473 insertions, 96 deletions
diff --git a/bridge/bridge.zig b/bridge/bridge.zig
index 0b56525..a7e0e58 100644
--- a/bridge/bridge.zig
+++ b/bridge/bridge.zig
@@ -21,8 +21,8 @@ const init_program = blk: {
@embedFile("k_console") ++ "\n" ++
@embedFile("k_vmm") ++ "\n" ++
@embedFile("k_fs") ++ "\n" ++
- @embedFile("k_io") ++ "\n" ++
@embedFile("k_vfs") ++ "\n" ++
+ @embedFile("k_io") ++ "\n" ++
@embedFile("k_seed") ++ "\n";
// gils shit
diff --git a/bridge/hosts.zig b/bridge/hosts.zig
index 7ce5650..caf8b0d 100644
--- a/bridge/hosts.zig
+++ b/bridge/hosts.zig
@@ -24,6 +24,14 @@ const scripts = [_]Script{
.{ .name = "tail", .src = @embedFile("k_gils_tail") },
};
+// /etc/ shit
+const EtcFile = struct { name: []const u8, src: []const u8 };
+const etc_files = [_]EtcFile{
+ .{ .name = "motd", .src = @embedFile("k_etc_motd") },
+ .{ .name = "profile", .src = @embedFile("k_etc_profile") },
+ .{ .name = "lung", .src = @embedFile("k_etc_lung") },
+};
+
// the actual framebuffer, the data layout feels pretty self explanatory
pub const Fb = struct {
ptr: [*]u8,
@@ -425,6 +433,25 @@ fn hostScriptSrc(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
}
// pass shit to revo
+fn hostEtcCount(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(etc_files.len));
+}
+
+// pass shit to revo
+fn hostEtcName(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
+ const i = argInt(usize, args, 0) orelse return HostResult.other("etc_name: bad index");
+ if (i >= etc_files.len) return HostResult.other("etc_name: out of range");
+ return HostResult.data(try vm.ownValueString(etc_files[i].name));
+}
+
+// pass shit to revo
+fn hostEtcSrc(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
+ const i = argInt(usize, args, 0) orelse return HostResult.other("etc_src: bad index");
+ if (i >= etc_files.len) return HostResult.other("etc_src: out of range");
+ return HostResult.data(try vm.ownValueString(etc_files[i].src));
+}
+
+// pass shit to revo
fn hostEvalScript(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
const sid = args[0].asString() orelse return HostResult.other("eval_script: not a string");
const src = vm.stringValue(sid);
@@ -487,6 +514,9 @@ pub fn passShitToRevo(vm: *revo.VM) !void {
try vm.registerGlobal("script_count", try vm.installHost("script_count", define(&[_]T{}, hostScriptCount)));
try vm.registerGlobal("script_name", try vm.installHost("script_name", define(&[_]T{.number}, hostScriptName)));
try vm.registerGlobal("script_src", try vm.installHost("script_src", define(&[_]T{.number}, hostScriptSrc)));
+ try vm.registerGlobal("etc_count", try vm.installHost("etc_count", define(&[_]T{}, hostEtcCount)));
+ try vm.registerGlobal("etc_name", try vm.installHost("etc_name", define(&[_]T{.number}, hostEtcName)));
+ try vm.registerGlobal("etc_src", try vm.installHost("etc_src", define(&[_]T{.number}, hostEtcSrc)));
try vm.registerGlobal("alloc_contig", try vm.installHost("alloc_contig", define(&[_]T{.number}, hostAllocContig)));
try vm.registerGlobal("blit_str", try vm.installHost("blit_str", define(&[_]T{ .number, .string }, hostBlitStr)));
try vm.registerGlobal("phys_to_str", try vm.installHost("phys_to_str", define(&[_]T{ .number, .number }, hostPhysToStr)));
diff --git a/build.zig b/build.zig
index 98bac24..e625977 100644
--- a/build.zig
+++ b/build.zig
@@ -89,6 +89,11 @@ pub fn build(b: *std.Build) void {
bridge_mod.addAnonymousImport("k_gils_" ++ g, .{ .root_source_file = b.path("gils/" ++ g ++ ".rv") });
}
+ // /etc/ bullshit
+ inline for (.{ "motd", "profile", "lung" }) |name| {
+ bridge_mod.addAnonymousImport("k_etc_" ++ name, .{ .root_source_file = b.path("etc/" ++ name) });
+ }
+
kernel.root_module.addImport("bridge", bridge_mod);
inline for (.{
diff --git a/etc/lung b/etc/lung
new file mode 100644
index 0000000..54c10ab
--- /dev/null
+++ b/etc/lung
@@ -0,0 +1,79 @@
+(((())))11111{{{}}}}}}[[[]]]]]]]-------_______)juvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvccccccvvvvvvccccccccccccccccccccccccccvvvvvvuuuuuuuuuuuuuuuunnnnnnnnnnnxxxxxxxxxxxxxxxrrrrrrrrrrrrrrrrrrrrrrrrjjjjjjjjjffjf)][}}
+||(((()))11111{{{{}}}}}[[[]]]]]]????----______-{tuuuuuuvvvvvvvvvvvvvvuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvccccccvvvvvvcccccccccccccccccccccccvvvvvvvvvuuuuuuuuuuuuunnnnnnnnnnnxxxxxxxxxxxxxxrrrrrrrrrrrrrrrrrrrjjjjjjjjjjjjjjjjjjff/{-_-][
+|||||(((()))111111{{}}}[[[[[[]]]]]??----________[fnuuuuuuuuuuuuuvvvvvvuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvcccccccccccccccccccccccccvvvccccccvvvvvvvvvuuuuuuuuuunnnnnnnnnnnnnnxxxxxxrrrrrrrrrrrrrrjjjjjjjjjrjjjjjjjjjjjjjjjjjjjjffft)~+[{{1
+\\\|||((())))1111111{{{}}[[[[[]]]]??----_________]|xuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvcccccccccccccccccccccccccvvvvvvvvvuuuuuuuuuuuuuuuunnnnnnnnnnnnnxxxxxxxxrrrrrrrrrrrrrrrjjjjjjjjjjjjjjjjjjjjjjjjjjjjjffftf\}<+{)))
+\\\\\||||(()))1111111{{{}}}}[[[[]]??----________+_?(ruuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvcccccccccccccccccccccvvvvvuuunnnnnnuuuuuuuuuuuuunnnnnnnnnnnnnnnxxxxxxrrrrrrrrrrrrrjjjjjjjjjjjjjjjjjfffffffffffjjjffffft/{~I~{||(
+/\\\\\\||((())))111111{{{}}}[[[[]]??-----_____+++++_1fnnnuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvuvvvvvvvvvvvvvcvvvvvvvvvvuuuuvvvvvuuuuunnnnnnnnnnnnnnnnnnnnnnnnnnnnnnxxxxxxxxxxxxrrrrrjjjjjjjjjjjjjjjjjjjjjjjjffffffffffffffffffftt\(]+<?)//\
+//\\\\\\\|||(((()))11111{{{}[[[[[]]]?------__++++++++{txnunnnnnuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvuuuuuunnnnnnnuuunnnnnnnnnnnnnnnnnnnnnnxxxxxxxxxxxnxxxxxxxrrrrrrrrjjjjjjjjjjjjjjjjjfffffffffffffffffffffffftttt//|}?]-])//(
+/t////\\\\\||((((()))1111{{{}}}[[]]]?------__+++++++~+]\xnnnnnnnnnnnnnnnnnnnnnnnnnnuuuuuuuuuuuuuuuvuuuuuuuuuuuuuuuuuvuuunnnxxrrjjjjjrrrrjjjjrjjjrrrrrrrrrrjjjjrrxrxrrrxxxxxxxxxxrrrrrrrrjjjjjjjjjjjjfffffffffffffftttttttttttttttttftt\{?_-?_](//1
+tttt////\\\|||(((()))11111{{}}}[[[[]]?-----__+++++++~~~?(rxxnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnuuuuuuuuuuuuuuuuuuuunnnnxxrrjfffttt///\\/tttttttttfffffffffft/\\///tttfjjrrrrrrrrrrrrrrrrjjjjjjjjjjjjjjfffffffffffffftttttttttttttttt////(_l><~+?[[}}
+ttttt//////\\|||((()))))111{}}}}}[[]]]?----__+++_++++~~~-(fxxxxnnnnnnnnnnnnnnnnnnnnnxxxnnnnunnnnnuuuuuuuuuuuuuunxjjjjjfjjft/\|||(()))(\//\\\|\||\\///\|(1}[[[}{1)((((|/tfjjjjjjjjjjjjjjjjjjjjjjjjjjffffffffffffffftttt|(1}[]][1\//////)-<___[1{{{{
+fttttttt///\\\\|||((())))111{{{}}[[[]]?---___+++_++~~~<<>~{frxxxxxxxxxxxxxnnnnnnnnnnxxxxnnnnnnnnnnunnnnnxxxxrjjft/\\\\||(1{}}}}}}}}}}?__]}}}}111{{1)1[-~>iii!!ii~_?}{1(|\\ttfjjjjjjjjjjjfffffffffffffffffffffftfftt|}-+<>!I;,^`:>_?[1{?__+_]))((()
+jffffttt//////\\\|||(((())11{{{}}}[[]]?---___+++_+~~~<<>ii<]/rrxrrxxxxxxxxxxxxxxxxxxnnnnnnnnnnnnnnnnnxxrrjjffttt//\(1}?~iI:,,,"""""""^`''^,,I<_--_++>I,`. .'`^``^,l+[(\/tttffffjjjjjffffffffttttftttttfffftttt\[~><<<il;,` '",:!<<_}1(((((
+jjjfffttttt////\\\\|||((()))111{}}[[[]]]?---_+++++~~~<<>iiii-|jrjrrrrrrrrrxxxxxxxxxxxxxxxxnnnxnnnnnnxrrjjtt/\\|(1{]_!,' .''.'. ..'`:<[(/tttttffffffffttttttttttttttttttttttt(_>!!lI:` .''''"I<_[{)(((((
+rrjjjjffttttt////\\\||||(())111{{}}[[]]]?---___++~~~<<<>i!!!!+(tjjjrrrrrrrrrrrrrxxxxxxxxxxxxxxxxxrrrrjft/\||(1}]_i" .`:-)\///ttftfftttttttttttttttt/////////(-l``^^`. '",",:l<?}{1))))))
+rrrrrjjfffttttt///\\||||(((())11{}}[[[]]???--__+~~~~<>>ii!!!!!>{tjjjjrrrrrrrrrrrrrxrrrrrrrrrrrjjjfftt/\|))1{[-i;' . .,-(\\//tttttttttttt////////\\\\\\\\\(?: .. "i>i!!i+?}{{1111111
+xxrrrrrjjjffttt////\\\||||(())11{{}}[[]]]??--__++~~<<>>i!!!!lll<[tjfffffffffffffffffjjjjjjjjjfftt/||())1}[?+l` ...'l?(\\//tttt/////////\\\\\\\\|||||\()?i:````^:!+?[]<ii><-]{{{1111111
+xxxxrrrjjjfffttttt//\\|||||(())11{{}[[[]]]?--___+~<<>>i!!!lllIII!](ttttttttttttttttffffffffftt//\|)))1{[-~l" '. '~1\\\////\\\\\\\||||||||(((((((((((()111111111}+ll<~+?]]][[}}}}}}
+xxxxrrrrjjjjffttttt//\\\\||||()111{}}}[]]]?--__+++~<>ii!!!llII;;::-)///////tttttttttttttt////\|(()11}?<!;". l[)|||\\\\\\\|||||||||(((()))))))((()))1111{}-<;I<-][[[[[]?-----
+xxxxxxrrrjjjfttttttt///\\||||(()11{{}}[[]]??-__+++~<>ii!!!lIII;:,,,>}|\\\\\\\\//////////\\|||(()){]_i:"' .l-1)(|||((((|||||||(((((()))))))))))1111{[<l!>I,:<[[[}}{}[]----
+nnxxxxxxrrrjjfffftttt///\\\||(()111{{}[[]]]??--_++~>>ii!!!llI;;:,"",i[(|||||\\\\\\\\///\\|((((1}?<I^. :~[1))(((((((((((()))))11111111111{{{{{{?illI`^I-[}{{{{{}[]]]]
+nnxnxxxxxrrrjjjjjfttttt//\\\||(())1{{}}[[]]??--_+~~<ii!!!!ll;;;:,"^^^l-1(((||||||||||||||()11[_>I"' .l-}11))))))))))))))111111{{{{{{{{{{{}?>llI, ,-[}}}}}}}}}}[[[
+unnnxxxxxrrrrjjjjjfttttt//\\||||()1{{{}}[]]]?--_+~~<ii!lllII;;;:,,"^`':+})))))(||||((((()1{]+>I"' ;+[{1111111111111111{{{{{{{{{{}}}}?>!!i!!!!~[}}}}}}}}}}}[[[
+unnnnxxxxxrrrrrrjjfttttt//\\\|||()11{{{}[]]]?--_+~~<ii!lllII;;;:,,"^`''"<[11)))(())))()1{]+iI,` :<?}{{{{{{{{{{{{{{{{{}}}}}}}}}]_>l!>_-?--?][}[[[[}}}}}}[[[
+uununxxxxxxrrrrrjjfftttt///\\\||()11{{{}[]]]?--__+~<ii!lllII;;::,,"^`'. `!?{{{{{1111{1{[-~!,' .......'```^^`. "<?[[[}}}}{{{{}}{{}}}}}[}}}]>;,I!<_-?][[[[[[[[[[[[[[[[[[[
+uuuuunxxxxxxxrrrrjjffffttt//\\\|(()1{{{}}[[]??--_+~<ii!lllII;:::,,"^`'.. .:~[}}}{{{}}[-~>l". .`",:;IIIIlll!!!!lI;,,,,,,::;IIII:"` `>-][}}}}}}}[[[[[[[[[[[]->:^;>_-____--???]]]]]]]]]]]]]]]
+vuuuuunnnxxxxrrrrrjjfffttt//\\\||()11{{}}[[]]??-_+~<ii!lllII;:::,,"^`'.. "i-]]][[[?_<l:"^`^ '":Ilii><<~~~~++++~<>i>>>>><<<>>>>il;" `!-]][[[[[[[]]]?_+++~iII!!;l~]]]?-_______----??]]]]]]]]
+vvvvuuunnxxxxxxrrrjjffftttt/\\\\|(()111{}}[[]]?-_+~~>i!!lII;::,,,"""^'.... `!_---?-<l:,:;;"' `,;!i><~~+++_---?????????--_++~~<<>i!I:. .I~???]]]][]]_>;":l>~+--+!l>-?]?????--_++___---???????
+vvvvuuunnnnnnxxxrrjjffftttt/\\\\||())11{}}[[]]?-_+~~>i!!lI;;:,,,""""^`'... 'I+--_>lIIl!I,`. .. `,;!>><~~~+_-?]]]]]]]]]]]]?--_+++~<<>!l;` ,<+___~<i!ll!<+----???-~!;I~?]]]]]??--____-----?????
+ccvvvvuuunnxxxxxrrrjjjjffttt/\\\\|(())1{}}[[]]?-_+~<>i!!lI;;:,,"^^^^^^``'.. .:<+~!!!!!l;"^`' .`' .`,;l><~+++__-][[[[[[[[[[]]]]]???-_+~~<i!I" .,li><<<+_-???????????_>I;l<-???????---------------
+zcccvvvuunnnxxxxrrrjjjjfftttt///\\|(()1{}}[[[]?-_+~<>i!!lI;:,,,"^^^^^^^^^````^:>~<!!!!I;::,"^. '^` .`,;li<~+__--??]][[[[[[[[[[[[[[]]??-_+~<>il,' "l<~_-----??????????-_+--------------------------
+zzccvvvuuunnxxxxxxrrjjjfftttt///\\\|()11}}}[[]]?_+~<ii!!lI;:,,,"^^^^^^^"""",:I!><ill!!llllI,^' .``. '^,;Ili<~++++__-??]]]][[[[[[[[[[]]]?-__+~<i!;^ ^I!<~+___---------------------------------------
+zzcccvvvuuunnnnxxxrrjjjfftttt///\\\|()11{}}[[[]?-+~<>i!llI;::,,"""^^^^^",:;Il>~<ilI!iiii!lI::"^' .`` '^:Il!><+____--??][]]]][[[[}}[[[[[]?--_+~<iil,' ."I>~+++_____________________------------------
+zXzzcvvvvuuunnnnnxrrrjjjftttt///\\\|()11{}}[[[]?-+~<>i!lI;;::,,""^"^^^",::;l~__<!II!<<>>>i!I;:"^ .. .`,I!><~+-??][[[[[}}[[[[[[[[}}}}[[[[]]?-__~>i!;^ ."l<++++_________________________----------_--
+zzzzzccvvuuunnnxxxrrrrrjffffttt/\\\|()11{}}[[]]--+++~>i!lI;::,,,,,,,:;l!lli-]?+iI::!~-??-+>lI,"` .^:I!>~+_?][[[}}{{{{{{{{{}}}}{{{{{{{{}[[]]?_+<il,' "!<~~~++++++++++++++++++_____________----__-
+Xzzzzccvvuuunnnxxxrrrrrjffffttt///\|()11{}}[[]?-_+++~<>ii!llI;,,::Il!iii!i_??_>I,":>-[[[?+>lI,' '";l>~-??]}}}{{1)))(()))111111))))))11{{{}[]-_~>l" `I<~~~++++++++++++++++++++++______________-
+YXXXzccccvuunnnxxxrrrrrjjfffttt///\\()11{}}[[]?_+~~~~~<>ii!!!I:,:;!iiii>+--_+>I;:;i-}1{{]_<l"' .`,;!<+_-][}{1111)((||||||((|||||||(((()))1}[?_~i;' ^I<~~~~~~~~~~~~~~~~~++++++++++++______----
+YXXXXzzccvvuunnnxxrrrrrjjfffttt///\\()11{}}[[]-_+~<<>>>iii!l!!IIl><<<<+_?]?-_>l;;l+{)(1[->I:,"^' .'`",l>~-?[{)(||\\\\\\\\\|||((())111{[?_+<i;` ^l<~~<~~~~~~~~~~~~~~~~~+++++++++_____----
+YYXXXzzcccvuunnnxxxrrrrjjfffftt///\\|(11{}}[[]?_~<<>>ii!!lllllll!i<_??]]]-+~>I;!i>-)(}_ili<>l,' .''' '^^^`'. ^l~?{(||||||((((){[-~~<<<>!lI;;::"`. ^l<<~~~~~~~~~~~~~~~~~~~++++++____-------
+YYXXXXzcccvuuunnxxxrrrrjjffffttt//\\|()1{}[[]]-_+~<>iiiii!I;;Ill!!>+-?]]_~iI;",l><~--<<+_~i;"`'''`";;,' '^,:;;;Il!!lI:^`^"l<-]{1)((()){}]_<;^. `I><<<<<<<<<<<<<~~~~~~~+++++__---------
+YYXXXXzzccvuuuunxxxrrrrjjffffftt//\\|()1{}[]??-_+~~~<<<><>!IIIl!>+_?]?-~>illI,"Ili<-[[]]_!;,:;I;,"";;:' .`"IllIl<+?[{1))11{}[?_>I"^^""^^^""",:;;;:,". ^li><<<<<<<<<<<<~<~~~~~++++___--------
+UUYYXXzzzcvuuuunxxxrrrrjjffffftt//\\|()1{}[]]?-_+++~++~<<i!lll!!lI!>~>!llllll;:I>_})){?<ll!><<~>;,,II:` ",. +{]+i!l!<-[{1))11}]_>;:Il!l:' .`. :!i>>>>>>>>>>>><<<<<~~~~++___-------?
+JJUYXXzzzcvuuuunxxxrrrrjjffffftt//\\|()1{}[[]?--____+~~+~~<>i!!l;:;:,"",;lIII:,;>?}}-~~?{1{]___+iI:ll:` '`^""^'.^I+?<i!lI;I>_[}{11}?<;,;><i>+?; :i; "I!iiiiiiiiiiiiii>>><<~~~++__------??
+JJUYYXXzzzcvuuunxxxrrrrjjffffftt//\\|()1{}[[]?----???-+~~~~~<>>!I;III:",;I;:;:::Ii~+]1\fff\11{}?+!Iiil" '^:Ili>><+---_+~<<il:;l<-][{[_i;,I><>!!>>il:,,:I;,`.. . "I!i!i!!!!!!!!!!!!!i><<<~++_----????
+JJUUUXXXzzcvuuunxxxrrrrjjffffftt//\\|()1{}[[]?------??---_+<>>>ilIl!!lI;;;;;;:,,"I-{\jxxrj/())1}-<!><i:. '^:l><~+_--??-_+~>!I;::I>-]][_<l:,:li>><~+_--?--+~>!l;:"` .`' ^;!!!!!!llII;;;;;;;;Illi><+_--???]]]
+JJJUUYXXzzcvuuunxxxrrrrjjffffftt//\\|(11{}[[?--__++~~~~~++~>!!lllIIlI;,"^^^"""^``:+1/jnnxjf\()11}-<~<i;`. '^,li~+-?][[[[]?_~ilII;;I>_]]]_<!;::;Ii>++_?][[]]?-+<i!l;^ '^",,` '^:Il!!!!lI;:,"^^````'```"I>_--?????]
+CJJJUYXXzzcvuuunxxxrrrrjjffffftt//\\()11}[[]?-_++~<>ii!!!!!lI;:,,"^^``'....'``'''"<1/rnnnxf/|(()1[??+iI,^. .`,Ii<_-?[}}}}]??_~>lllII!+][[[-<iI;IIli<+-]}{111{}[?_~>il" '````.'.`,"'..':!>~>I,",^ 'i+-??????
+CCJJUYXXzzcvuuunxxxrrrrjjffffftt//\\()1{}[[]?-__+~<i!lIII;;::,^^`'''. .. .">?)rnnnxf/\\\()1{}?+>I:. .'":li<+-?[[[[[]??_~>!!ll!>-[}}[-~!I;Ili~_-][{111111{[?_~>l" ."l, .l?]_I . I<_-?----
+CCJUUYYXXzzvuuunxxxxrrjjjfffftt///\|(11{}[[]?___+~>i!lI;;::,""^``'... ^ll>1jxxxt)(tt/|()){?_>:. '`":Ii<+_???]]][[]?_<ii!l!<?[}}}?~iIIli<_][}}{{{{{{}}[?_~il" .`. "!il" ',IIIl!i>
+CCCJUYYXXzzvuuunxxxxrrjjjfffftt///\|(11{}[[]?___+~>i!lI;;:,,"^^``'''....... .`^.^~)fff(-?\t///\(){?>:'..'^",I!>~~+_-][}{{{}]+>!l!>_[}{{}?+iI;I>~?[{1{}}}}}[]]?_+<!;` '"^ ';I;" "III!i>>
+LCJJUYYXXzzvuuunxxxxrrjjjfffftttt/\|()1{}[[]?_+~~>i!lI;:::,""^`''''.....''. .'' l[(||)--)\///\||)]<:'..'`^";l!ii<+-]}{{1)1[+iI!<_?[{{{{[-<!::l~]}11{{{{}[[]?_+<iI". '`' 'I!l;. :!!i><~~
+LCJJUYYXXzzvuuunxxxxrrjjjfffftt//\||)1{}}[]?-++<<i!llI;:::,""^`''''....''' .' "!+_--__])//t//\|[<;`''``^,;I!ii>~_][{{1)1]<li+-]][{}}}[]_>l,,>?{111{{}[]?-+~<iI,' .'''. ,+??-I 'i?]?????
+LCJJJYYXXzzvuuunxxxxrrrjjjffftt//\|()1{}[]]?_+~<>i!lII;:::,"^`'''.....''`' ^,;>-]+<~?1/tt//|]>;"^`^^,:li>~~++-][{11){_~+]}{}}{1111{}]+>I:!_{11){{}]?-+~<iI:` ``' '>[{{1-: `:-11{{{{{
+QLCJJYYXXzzvuuunxxxxrrrjjjtttt///\|(){{[[]??_+~<>i!lII:::,""^`'''....'```' .``',>?]+>~-1/ft/\1+l:,"^",;l!><<~+_-?[}{{{}???[}}{1(\/|){}]_<il~]{)1){}[?-_~<iI:^. .`' :_1)1)[+: ^i?)|\\\\\
+QLCJJYYYXzzvuuunxxrrrjjjjfttt///\\|(1{}[[]??_+~<>i!lI;:::,"^^`'''....`""^' `:,`.':<?[+<+[)\\|\)?>:,,"",:l!i<~~~++_?][}}}}[?____-[{(){[-~<<<><-[{)11{}]-_+<iI,^. `' :+)(((1?i". ^l?)|\\\\\
+LLCJUUYYXzzvuuunxxrrrjjfftttt///\|()1{}[]]?-+~<>>!!lI;:,,,"^^`''.....^"^' 'l>I,`'"i?]_ii-{(||()}+l"`^''^,I!!>~~+++_-?][[[[[?_+++-?][[]?+~<<<~-][}}}{}}]-+~>l:^' '^. ,+(\\/\{<:' `l-1|\\\\\
+LLCJUYYXXzzvuuuxxrrrrjjffttt////\()11{}[]?-_+~<>>!!lI;:,""^^``''.....'^.. ,i~<l:^`:+11?~<?1(((){->I^. `:l!>~~++_--?]]][[[]??][}{{{{}}}}]??]][[[}}}}}]-+~iI,` .`` ^<)|///1<;` .;~}(\||||
+LLJJUYXXzzcuuunxxxrrjjffffttt//\|()1{}[]]?-_~~<>i!lI;;:,""^```''..... 'l>i+-<;^^l}/|?_-?{))(1?>l;^ `Ii>~++++_-??][[[[[}}{1)))(((()1{}}[[[[[}}}}}]-+~iI". .. ^<{(\\\1<;` ^i-1|||||
+LLJJUYXXzcvuuunxxxrjjjfffttt//\\|)1{{}[]]?_+~<>i!llI;:,,"^^```'.. ':~~!-[+!I;l+{){{1}{11{[>l;,' ^!>~+++___--?]][[[}}{11))1)))1{{{}}[[[][][]]]-+~!:^ '!}(\\\1~I` 'I+}(((((
+CCJUUYXXzcvuunxxxrrjjffttttt/\\\|)1{}[[]?-_+~<>i!llI;,"""^```''. ,i~>l]}_>i!ll_)\\|1}?__~l;,". `I>++__________+_-?][[[[[}}}[]????-????]??]]?+<l:` .'l])|||1_!". .,>[)))))
+CCJUUYXXzcvunxxrrrjjjffttt//\\\|()1{}[]??-+~<>i!lII;:,"^^^``'''. 'I~~>!]}_<~_+~{/t|{[_~<iI,^`' ,!~++__+~>;"^''`^,;li<~~~<<>i!I:,,,,;!<+--_~i;". 'I?1())1?i"' ^!?{11{1
+CCJUUYXXzcvunxxrrrjjjffttt//\\\|(1{{}]]??-+~<ii!lI;::,""^^``''.. ',l+]?+<><~<<>i<1\|[_~>l,",,` "!~+___+~>l:^. .";Illl:^. ^:!iii!I"' "-{11{]i"' ';~]{11{
+CCJUYXXzcvuunxrrrjjfffttt//\\\|(){{}[]?--_+<>i!llI;,""^^^^`'''.. `>__-?+i:";><l,l~?-_<i!l,.. "l<+__+~~~>l:""^````''....''```":l><~~~>l,' I-1{]i". ,>?}{{}
+JJUYYXzzvuunxxrrrjjfftttt//\\|()1{}[[]?-_+~>i!!lI;:,""^^^``'.... ,i+_~!ll;^ '":;:I!!!!I,^. ;<++++++~<iI;:;IllllI;;;::::;!>~~++++~>I" '<[]>^. "i]{111
+JJUYXzzcvuuxxrrjjfftttt///\\\|()1}}[[?-_++<i!lIII;:,""^````'......^!__~!,' .'`^",:,"",,` ,<++____+~<i!lllIIIIIIIIII!i<~+~~~~~<!:' :_<" ^!?)|||
+JJUYXzcvuunxrrjjffftttt//\\\|()1{}[[]-__~~>i!lIII:,,"^^````'...':~[?!' .'`^^``^` ^i++___--?--__++~~<<<<~~__-_++~~~~<i:' '` 'I_)\\\
+UUYXXzcvunxxrrjjfftttt//\\\||(1{}[[]?-_+~<>i!lII;:,"^^^````'.."<-_: ..'``` `l<+_--?]]]]?????------?---_+~<<<!:`. ;+1|\\
+UUYXzccvunxxrjffffttt///\\||(){{}[[]?__~<<>i!lI;;::"^^^````'^!_!. .`^` 'Ii<_--?????]]]]]]?????-___+<>iI,`.. . ,~}|//
+UYXzcvvunxxrjfffttt///\\\\|()1{}[[]]-_+~<>i!lI;;::,"^^^```^!-_I ";` .. ";l>+_-_????????]????-___+~i;"`'''. ^<](//
+YYXzvvunnxrjjfftttt//\/\|||()1{[[]?--_+<>>i!II;::,,"^^^^,!~+I. "I. .. ^,;I!i<~~~~++++++++++~~<>!I:^''''`. 'l-)//
+XXzcvunxxrjjfftt////\\\||())1{}[]]?-_+~<>>!lII;:,,,"^";!il' .' .^",:::;IIIIl!iiiii!!!lIII;:"^`''' .I-(jn
+Xzcuunxxrrjfftt////\\|||()1{}[[]]?--_+<<>i!lI;::,,,":!>: `^"",,,,;Ili><~__-_+++~<il:,^``'' ,_\vJ
+zcvunxxrrjffftt////\\||((1{{}[]]?-__+<<>!!lII;:::::I;' '^,,,"",:Il!><+-?]]??_+>l;,^``'. `~(nY
+zcunxxrjjfftt///\\\\|||()1{}[[]?--_+~<>i!lllI;::;l;` `","""",;I;;;l!<_--+i;:,"^```'. ;]tv
+vuunxrrjjfft//\\\\|||())1{}[[]]?-_+~~<ii!lllIII><i, ^"""""",:;;:,,;!i!I,""""^^``' `+|x
+unxxrjjfftt/\\\\||||())1{}}[]]??-_+~<>iii!lIIIl+-; '``^^`^",:;:,""""^"",,^`''. . ,_(
+nxxrjjffttt/\\|||||()11{}[]]]]?-__+~~<>ii~?]-~~+!` .``^^^^",::::::::;:,"'. 'i}
+xxrjffttt//\\||||())1{}}[]]]???-_+~~~~+[/fjf\}!. '`^^^`'``^"""""`. l]
+xrjjff///\\\||(|(()11{}[]]]]?--_+~~~~]/xxf\[i' .'``'. ,_
+jffftt/\\\|||((())1{{}]]??--__++~<<<]tnuj1<. .''. ^<
diff --git a/etc/motd b/etc/motd
new file mode 100644
index 0000000..f252b8e
--- /dev/null
+++ b/etc/motd
@@ -0,0 +1 @@
+why the hell are you using this os?
diff --git a/etc/profile b/etc/profile
new file mode 100644
index 0000000..7cd7a19
--- /dev/null
+++ b/etc/profile
@@ -0,0 +1,8 @@
+# acts like .bash_profile or .zsh_profile
+
+const motd_size = fs:size("/etc/motd")
+if motd_size > 0 do
+ puts("\n")
+ puts(fs:read_bytes("/etc/motd", 0, motd_size))
+ puts("\n")
+end
diff --git a/gils/cat.rv b/gils/cat.rv
index 0666304..cb0df34 100644
--- a/gils/cat.rv
+++ b/gils/cat.rv
@@ -5,6 +5,5 @@ const parsed = arg_name(context.rest, 0)
if parsed.name:len() == 0 do fail("usage: cat <path>\n") end
else do
const path = expand_path(parsed.name)
- if vfs_owns(path) do vfs_cat(path) end
- else do fs:cat(path) end
+ vfs:cat(path)
end
diff --git a/gils/cp.rv b/gils/cp.rv
index 6fd06a8..e92ce21 100644
--- a/gils/cp.rv
+++ b/gils/cp.rv
@@ -8,13 +8,13 @@ if context.argv:len() < 3 do
end else do
const source = expand_path(context.argv[1])
const destination = expand_path(context.argv[2])
- const size = fs:size(source)
+ const size = vfs:size(source)
if size < 0 do
fail("cp: #{source}: no such file\n")
end else do
- const contents = if (size > 0) fs:read_bytes(source, 0, size) else ""
- if (fs:store(destination, contents) == 1)
+ const contents = if (size > 0) vfs:read_bytes(source, 0, size) else ""
+ if (vfs:store(destination, contents) == 1)
puts("#{source} -> #{destination}\n")
end
end
diff --git a/gils/ed.rv b/gils/ed.rv
index 023ce15..b3d4bfc 100644
--- a/gils/ed.rv
+++ b/gils/ed.rv
@@ -211,7 +211,7 @@ fn ed_write(state, command) do
const contents = ed_join(state.lines)
- fs:store(path, contents)
+ vfs:store(path, contents)
state.path = path
state.dirty = :false
puts("#{contents:len()}\n")
@@ -267,7 +267,7 @@ fn ed_run_file(state, line, parsed) do
const path = expand_path(rest:split(" ")[0])
- if fs:size(path) < 0 do
+ if vfs:size(path) < 0 do
puts("?\n")
return :nil
end
@@ -337,10 +337,10 @@ fn gils_ed(context) -> :hold do
else ""
if ed_state.path:len() > 0 do
- const size = fs:size(ed_state.path)
+ const size = vfs:size(ed_state.path)
if size > 0 do
- const contents = fs:read_bytes(ed_state.path, 0, size)
+ const contents = vfs:read_bytes(ed_state.path, 0, size)
const raw_lines = contents:split("\n")
for index in 0..raw_lines:len() do
diff --git a/gils/head.rv b/gils/head.rv
index eb50087..c124ed3 100644
--- a/gils/head.rv
+++ b/gils/head.rv
@@ -1,11 +1,11 @@
# gimme some head lung
fn file_lines(path) -> table | :nil do
- const size = fs:size(path)
+ const size = vfs:size(path)
if (size < 0)
return :nil
- const contents = if (size > 0) fs:read_bytes(path, 0, size) else ""
+ const contents = if (size > 0) vfs:read_bytes(path, 0, size) else ""
const raw_lines = contents:split("\n")
let result = {}
for index in 0..raw_lines:len() do
diff --git a/gils/ls.rv b/gils/ls.rv
index 37f4b05..4afbb91 100644
--- a/gils/ls.rv
+++ b/gils/ls.rv
@@ -3,13 +3,4 @@
const context = env.ctx
const target = if (context.argv:len() > 1) expand_path(context.argv[1]) else wd.path
-if vfs_owns(target) do
- vfs_ls(target)
-end else do
- const count = fs:ls(target)
- if target == "/" do
- puts(" proc/\n")
- end else if count == 0 do
- puts(" (empty)\n")
- end
-end
+vfs:ls(target)
diff --git a/gils/mkdir.rv b/gils/mkdir.rv
index 9da7689..f701ac9 100644
--- a/gils/mkdir.rv
+++ b/gils/mkdir.rv
@@ -5,5 +5,5 @@ const context = env.ctx
if context.argv:len() < 2 do
fail("usage: mkdir <path>\n")
end else do
- fs:mkdir(expand_path(context.argv[1]))
+ vfs:mkdir(expand_path(context.argv[1]))
end
diff --git a/gils/mv.rv b/gils/mv.rv
index d44b898..d87cb28 100644
--- a/gils/mv.rv
+++ b/gils/mv.rv
@@ -6,14 +6,14 @@ if context.argv:len() < 3 do
end else do
const source = expand_path(context.argv[1])
const destination = expand_path(context.argv[2])
- const size = fs:size(source)
+ const size = vfs:size(source)
if size < 0 do
fail("mv: #{source}: no such file\n")
end else do
- const contents = if (size > 0) fs:read_bytes(source, 0, size) else ""
- if fs:store(destination, contents) == 1 do
- fs:unlink(source)
+ const contents = if (size > 0) vfs:read_bytes(source, 0, size) else ""
+ if vfs:store(destination, contents) == 1 do
+ vfs:unlink(source)
puts("#{source} -> #{destination}\n")
end
end
diff --git a/gils/rm.rv b/gils/rm.rv
index 8c954f3..916ee3f 100644
--- a/gils/rm.rv
+++ b/gils/rm.rv
@@ -6,5 +6,5 @@ const parsed = arg_name(context.rest, 0)
if parsed.name:len() == 0 do
fail("usage: rm <path>\n")
end else do
- fs:rm(expand_path(parsed.name))
+ vfs:rm(expand_path(parsed.name))
end
diff --git a/gils/tail.rv b/gils/tail.rv
index c0ce1df..b5513a6 100644
--- a/gils/tail.rv
+++ b/gils/tail.rv
@@ -2,11 +2,11 @@
# and its between my legs
fn file_lines(path) -> table | :nil do
- const size = fs:size(path)
+ const size = vfs:size(path)
if (size < 0)
return :nil
- const contents = if (size > 0) fs:read_bytes(path, 0, size) else ""
+ const contents = if (size > 0) vfs:read_bytes(path, 0, size) else ""
const raw_lines = contents:split("\n")
let result = {}
diff --git a/gils/touch.rv b/gils/touch.rv
index 3032e96..5e27309 100644
--- a/gils/touch.rv
+++ b/gils/touch.rv
@@ -5,9 +5,9 @@ if context.argv:len() < 2 do
fail("usage: touch <path>\n")
end else do
const path = expand_path(context.argv[1])
- if fs:is_dir(path) do
+ if vfs:is_dir(path) do
fail("touch: #{path}: is a directory\n")
- end else if fs:size(path) < 0 do
- fs:store(path, "")
+ end else if vfs:size(path) < 0 do
+ vfs:store(path, "")
end
end
diff --git a/gils/tree.rv b/gils/tree.rv
index d146403..4aad0df 100644
--- a/gils/tree.rv
+++ b/gils/tree.rv
@@ -1,7 +1,7 @@
# recursive directory listing
fn tree_walk(path, prefix) do
- const items = fs:entries(path)
+ const items = vfs:entries(path)
if (items == :nil)
return :nil
@@ -29,17 +29,9 @@ end
const context = env.ctx
const target = if (context.argv:len() > 1) expand_path(context.argv[1]) else wd.path
-if vfs_owns(target) and target != "/" do
- fail("tree: #{target}: virtual dir\n")
-end else if target != "/" and fs:is_dir(target) == :false do
+if vfs:is_dir(target) == :false do
fail("tree: #{target}: not a directory\n")
end else do
puts("#{target}\n")
tree_walk(target, "")
- # /proc is the one thing not on disk so tack it on at root
- if target == "/" do
- puts("`-- proc/\n")
- puts(" |-- uptime\n")
- puts(" `-- meminfo\n")
- end
end
diff --git a/gils/wc.rv b/gils/wc.rv
index 75a3ed2..33dd1e6 100644
--- a/gils/wc.rv
+++ b/gils/wc.rv
@@ -5,12 +5,12 @@ if context.argv:len() < 2 do
fail("usage: wc <path>\n")
end else do
const path = expand_path(context.argv[1])
- const size = fs:size(path)
+ const size = vfs:size(path)
if size < 0 do
fail("wc: #{path}: no such file\n")
end else do
- const contents = if (size > 0) fs:read_bytes(path, 0, size) else ""
+ const contents = if (size > 0) vfs:read_bytes(path, 0, size) else ""
let line_count = 0
let word_count = 0
let in_word = :false
diff --git a/kernel/io.rv b/kernel/io.rv
index af28403..43d43a9 100644
--- a/kernel/io.rv
+++ b/kernel/io.rv
@@ -3,12 +3,12 @@
global io = {
fn open(self, path, mode) -> { path: string, offset: num } do
if mode == "w" do
- fs:store(path, "")
+ vfs:store(path, "")
end
let offset = 0
if mode == "a" do
- const size = fs:size(path)
+ const size = vfs:size(path)
if (size > 0)
offset = size
end
@@ -17,23 +17,23 @@ global io = {
end,
fn read(self, handle, count) -> string do
- const data = fs:read_bytes(handle.path, handle.offset, count)
+ const data = vfs:read_bytes(handle.path, handle.offset, count)
handle.offset += data:len()
return data
end,
fn read_all(self, handle) -> string do
- const size = fs:size(handle.path)
+ const size = vfs:size(handle.path)
if (size <= handle.offset)
return ""
- const data = fs:read_bytes(handle.path, handle.offset, size - handle.offset)
+ const data = vfs:read_bytes(handle.path, handle.offset, size - handle.offset)
handle.offset += data:len()
return data
end,
fn write(self, handle, data) -> num do
- fs:write_at(handle.path, handle.offset, data)
+ vfs:write_at(handle.path, handle.offset, data)
handle.offset += data:len()
return data:len()
end,
diff --git a/kernel/seed.rv b/kernel/seed.rv
index 9dc2dc5..95ed632 100644
--- a/kernel/seed.rv
+++ b/kernel/seed.rv
@@ -23,16 +23,9 @@ fn seed_fs() do
fs:mkdir("/etc")
fs:mkdir("/home")
- fs:store("/etc/motd", "welcome to revel")
- fs:store("/etc/profile", """
- # /etc/profile runs once at shell startup, keep it quick
-
- const motd_size = fs:size("/etc/motd")
- if motd_size > 0 do
- puts(fs:read_bytes("/etc/motd", 0, motd_size))
- puts("\n")
- end
- """)
+ for index in 0..etc_count() do
+ fs:store("/etc/#{etc_name(index)}", etc_src(index))
+ end
fs:store("/home/balls.txt", "its lowk insane how big my balls are lol jk\n\t- hachem")
fs:store("/home/i have big balls.txt", "dude my balls are actually massive lol jk\n\t- hachem")
diff --git a/kernel/shell.rv b/kernel/shell.rv
index e016d18..e5f4caf 100644
--- a/kernel/shell.rv
+++ b/kernel/shell.rv
@@ -128,9 +128,7 @@ fn cmd_cd(context) do
const target = if (arg == "..") parent_of(wd.path) else expand_path(arg)
- if target == "/proc"
- or target == "/bin"
- or fs:is_dir(target) do
+ if vfs:is_dir(target) do
wd.path = target
end else do
fail("cd: #{arg}: not a directory\n")
diff --git a/kernel/vfs.rv b/kernel/vfs.rv
index 6df71cc..6547595 100644
--- a/kernel/vfs.rv
+++ b/kernel/vfs.rv
@@ -1,12 +1,25 @@
-# shitty vfs implementation
-# proc and /bin arent on disk, theyre completely virtual
+# vfs mount table
+#
+# tools only ever touch vfs not fs now since they never know or care whether a path is a real
+# file on disk or something, so they can read/write to shit like /dev/null for example
-const TASK_STATES = { "free", "ready", "dead", "blocked" }
+const T_FILE = 1
+const T_DIR = 2
+const T_CHAR = 3 # stream
+
+fn parent_dir(path) -> string do
+ const parts = path:split("/")
+ let out = ""
+ for index in 0..(parts:len() - 1) do
+ if (parts[index] != "")
+ out = out ~ "/" ~ parts[index]
+ end
+ return if (out == "") "/" else out
+end
-global vfs_owns = fn(path) -> bool do
- if (path == "/proc" or path:starts_with?("/proc/"))
- return :true
- return :false
+fn leaf(path) -> string do
+ const parts = path:split("/")
+ return parts[parts:len() - 1]
end
global parse_pid = fn(text) -> num do
@@ -24,39 +37,307 @@ global parse_pid = fn(text) -> num do
return number
end
-global vfs_ls = fn(path) do
- if path == "/proc" do
- puts(" uptime\n meminfo\n")
+const TASK_STATES = { "free", "ready", "dead", "blocked" }
+
+const procfs = {
+ writable = :false,
+
+ fn body(self, path) -> string | :nil do
+ if (path == "/proc/uptime")
+ return "#{math.floor(uptime() / 100)}s\n"
+ if (path == "/proc/meminfo")
+ return "#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n"
+
+ if path:starts_with?("/proc/") do
+ const pid = parse_pid(path[6..])
+ if (pid >= 0 and pid < task_max() and task_state(pid) != 0)
+ return "pid #{pid}: #{TASK_STATES[task_state(pid)]}\n"
+ end
+
+ return :nil
+ end,
+
+ fn entries(self, path) -> table | :nil do
+ if (path != "/proc")
+ return :nil
+
+ let out = {
+ { name = "uptime", type = T_FILE, size = self:size("/proc/uptime") },
+ { name = "meminfo", type = T_FILE, size = self:size("/proc/meminfo") },
+ }
for pid in 0..task_max() do
if (task_state(pid) != 0)
- puts(" #{pid}\n")
+ out:push({ name = "#{pid}", type = T_FILE, size = self:size("/proc/#{pid}") })
end
- end else do
- puts("ls: #{path}: no such directory\n")
- end
+
+ return out
+ end,
+
+ fn is_dir(self, path) -> bool do
+ return path == "/proc"
+ end,
+
+ fn size(self, path) -> num do
+ const b = self:body(path)
+ if (b == :nil)
+ return -1
+ return b:len()
+ end,
+
+ fn read_bytes(self, path, offset, length) -> string do
+ const b = self:body(path)
+ if (b == :nil)
+ return ""
+
+ let stop = offset + length
+ if (stop > b:len())
+ stop = b:len()
+ if (offset >= stop)
+ return ""
+
+ return b[offset..stop]
+ end,
+}
+
+const DEV_SAMPLE = 64
+
+fn dev_size(name) -> num do
+ if (name == "zero" or name == "random")
+ return DEV_SAMPLE
+ if (name == "null" or name == "full")
+ return 0
+ return -1
end
-global vfs_cat = fn(path) do
- if path == "/proc/uptime" do
- puts("#{math.floor(uptime() / 100)}s\n")
- return :nil
- end
+global devfs = {
+ writable = :true,
+ rng = 0,
- if path == "/proc/meminfo" do
- puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n")
- return :nil
- end
+ # random bs go
+ fn next_byte(self) -> num do
+ if (self.rng == 0)
+ self.rng = (uptime() band 0xffffffff) bor 1
+
+ let x = self.rng
+ x = x bxor ((x shl 13) band 0xffffffff)
+ x = x bxor (x shr 17)
+ x = x bxor ((x shl 5) band 0xffffffff)
+ self.rng = x band 0xffffffff
- if path:starts_with?("/proc/") do
- const pid = parse_pid(path[6..])
- if pid >= 0 and pid < task_max() and task_state(pid) != 0 do
- puts("pid #{pid}: #{TASK_STATES[task_state(pid)]}\n")
+ return self.rng band 0xff
+ end,
+
+ fn entries(self, path) -> table | :nil do
+ if (path != "/dev")
return :nil
+
+ const names = { "null", "zero", "random", "full" }
+ let out = {}
+ for index in 0..names:len() do
+ const name = names[index]
+ out:push({ name = name, type = T_CHAR, size = dev_size(name) })
end
- puts("cat: #{path}: no such file\n")
- return :nil
- end
+ return out
+ end,
- puts("cat: #{path}: no such file\n")
-end
+ fn is_dir(self, path) -> bool do
+ return path == "/dev"
+ end,
+
+ fn size(self, path) -> num do
+ return dev_size(leaf(path))
+ end,
+
+ fn read_bytes(self, path, offset, length) -> string do
+ const name = leaf(path)
+
+ if name == "zero" do
+ let out = ""
+ for index in 0..length do out = out ~ string.of_ascii(0) end
+ return out
+ end
+
+ if name == "random" do
+ let out = ""
+ # 33..126 is the printable ascii range
+ for index in 0..length do out = out ~ string.of_ascii(33 + (self:next_byte() band 0x3f)) end
+ return out
+ end
+
+ return "" # null and full read as empty
+ end,
+
+ fn store(self, path, text) -> num do
+ const name = leaf(path)
+ if (name == "null")
+ return 1
+ if name == "full" do
+ fail("#{path}: no space left on device\n")
+ return 0
+ end
+
+ fail("#{path}: read-only device\n")
+ return 0
+ end,
+
+ fn write_at(self, path, offset, text) do
+ self:store(path, text)
+ end,
+}
+
+global vfs = {
+ mounts = {
+ { at = "/proc", fs = procfs },
+ { at = "/dev", fs = devfs },
+ },
+
+ fn mount(self, at, backend) do
+ self.mounts:push({ at = at, fs = backend })
+ end,
+
+ fn backend(self, path) do
+ let best = :nil
+ for index in 0..self.mounts:len() do
+ const m = self.mounts[index]
+ if (path == m.at or path:starts_with?(m.at ~ "/")) do
+ if (best == :nil or m.at:len() > best.at:len())
+ best = m
+ end
+ end
+ return if (best == :nil) fs else best.fs
+ end,
+
+ fn children_of(self, dir) -> table do
+ let out = {}
+ for index in 0..self.mounts:len() do
+ const at = self.mounts[index].at
+ if (parent_dir(at) == dir)
+ out:push(leaf(at))
+ end
+ return out
+ end,
+
+ fn entries(self, path) -> table | :nil do
+ let out = self:backend(path):entries(path)
+
+ const kids = self:children_of(path)
+ if kids:len() > 0 do
+ if (out == :nil)
+ out = {}
+ for index in 0..kids:len() do
+ out:push({ name = kids[index], type = T_DIR, size = 0 })
+ end
+ end
+
+ return out
+ end,
+
+ fn is_dir(self, path) -> bool do
+ for index in 0..self.mounts:len() do
+ if (self.mounts[index].at == path)
+ return :true
+ end
+ return self:backend(path):is_dir(path)
+ end,
+
+ fn size(self, path) -> num do
+ return self:backend(path):size(path)
+ end,
+
+ fn read_bytes(self, path, offset, length) -> string do
+ return self:backend(path):read_bytes(path, offset, length)
+ end,
+
+ fn store(self, path, text) -> num do
+ const b = self:backend(path)
+ if (b == fs)
+ return fs:store(path, text)
+ if b.writable == :false do
+ fail("#{path}: read-only filesystem\n")
+ return 0
+ end
+ return b:store(path, text)
+ end,
+
+ fn write_at(self, path, offset, text) do
+ const b = self:backend(path)
+ if b == fs do
+ fs:write_at(path, offset, text)
+ return :nil
+ end
+ if b.writable == :false do
+ fail("#{path}: read-only filesystem\n")
+ return :nil
+ end
+ b:write_at(path, offset, text)
+ end,
+
+ fn mkdir(self, path) do
+ if self:backend(path) != fs do
+ fail("#{path}: read-only filesystem\n")
+ return :nil
+ end
+ fs:mkdir(path)
+ end,
+
+ fn unlink(self, path) do
+ if self:backend(path) != fs do
+ fail("#{path}: read-only filesystem\n")
+ return :nil
+ end
+ fs:unlink(path)
+ end,
+
+ fn rm(self, path) do
+ if self:backend(path) != fs do
+ fail("rm: #{path}: read-only filesystem\n")
+ return :nil
+ end
+ fs:rm(path)
+ end,
+
+ fn cat(self, path) do
+ const b = self:backend(path)
+ if b == fs do
+ fs:cat(path)
+ return :nil
+ end
+
+ const sz = b:size(path)
+ if sz < 0 do
+ fail("cat: #{path}: no such file\n")
+ return :nil
+ end
+
+ puts(b:read_bytes(path, 0, sz))
+ end,
+
+ fn ls(self, path) do
+ const items = self:entries(path)
+
+ if items == :nil do
+ const sz = self:size(path)
+ if (sz >= 0)
+ puts(" #{leaf(path)} #{sz} bytes\n")
+ else
+ fail("ls: #{path}: no such directory\n")
+ return :nil
+ end
+
+ if items:len() == 0 do
+ puts(" (empty)\n")
+ return :nil
+ end
+
+ for index in 0..items:len() do
+ const entry = items[index]
+ if (entry.type == T_DIR)
+ puts(" #{entry.name}/\n")
+ else if (entry.type == T_CHAR)
+ puts(" #{entry.name}\n")
+ else
+ puts(" #{entry.name} #{entry.size} bytes\n")
+ end
+ end,
+}