From 52dab7fc85d877e80e3032f0afabae906adebad8 Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 4 Oct 2026 16:03:42 +0200 Subject: feat: fs tree and free list alloc --- kernel/shell.rv | 110 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 12 deletions(-) (limited to 'kernel/shell.rv') diff --git a/kernel/shell.rv b/kernel/shell.rv index f72387a..40930c5 100644 --- a/kernel/shell.rv +++ b/kernel/shell.rv @@ -19,10 +19,14 @@ fn cmd_help() do help_row("zoom in|out", "scale the font") help_row("echo ", "print it back") puts("\n files\n") - help_row("ls", "list files") - help_row("cat ", "print a file") - help_row("write ", "create or overwrite") - help_row("rm ", "delete a file") + help_row("ls [path]", "list a directory") + help_row("cd ", "change directory") + help_row("pwd", "print working dir") + help_row("mkdir ", "make a directory") + help_row("cat ", "print a file") + help_row("edit ", "line editor, . to save") + help_row("write ", "create or overwrite") + help_row("rm ", "delete a file or empty dir") help_row("mkfs", "format the disk") puts("\n programs\n") help_row("run", "list programs") @@ -34,7 +38,7 @@ fn welcome() do let fsline = "no filesystem" if fs.ready do fsline = "revelfs mounted" end puts("\n") - puts(" a tiny os whose brain lives in revo, zig only touches the metal\n") + puts(" kernel written in revo - by an alcoholic\n") puts(" #{(mem_total() shr 20)} MiB ram | #{fsline} | #{prog_count()} programs\n") puts(" type help to see what it does\n\n% ") end @@ -43,7 +47,6 @@ fn arg_name(line, start) do let quoted = :false let begin = start if (begin < line:len() and line[begin] == "\"") do begin += 1 quoted = :true end - # scan to the end of the name, a closing quote or a space depending on how it opened let i = begin if quoted do while (i < line:len() and line[i] != "\"") do i += 1 end @@ -52,29 +55,103 @@ fn arg_name(line, start) do while (i < line:len() and line[i] != " ") do i += 1 end end const name = line[begin..i] - # step past the closing quote and the separating space so rest points at the text let rest = i if (quoted and rest < line:len()) do rest += 1 end if (rest < line:len() and line[rest] == " ") do rest += 1 end { name = name, rest = rest } end +global wd = { path = "/" } + +global editor = { active = :false, path = "", buf = "" } + +fn editor_start(path) do + editor.active = :true + editor.path = path + editor.buf = "" + const sz = fs:size(path) + if sz > 0 do + editor.buf = fs:read_bytes(path, 0, sz) + puts(editor.buf) + end + puts("-- editing #{path}, a single . on a line saves and exits --\n") +end + +fn editor_line(line) do + if line == "." do + fs:store(editor.path, editor.buf) + editor.active = :false + puts("saved #{editor.path} (#{editor.buf:len()} bytes)\n% ") + end + else do editor.buf = editor.buf ~ line ~ "\n" end +end + +fn cmd_edit(line) do + const a = arg_name(line, 5) + if a.name:len() == 0 do puts("usage: edit \n% ") return :nil end + editor_start(abspath(a.name)) +end + +fn abspath(arg) do + if arg:len() == 0 return wd.path + let p = arg + if arg[0] != "/" do + if wd.path == "/" do p = "/#{arg}" end + else do p = "#{wd.path}/#{arg}" end + end + while (p:len() > 1 and p[p:len() - 1] == "/") do p = p[0..(p:len() - 1)] end + return p +end + +fn parent_of(path) do + if path == "/" return "/" + let i = path:len() - 1 + while (i > 0 and path[i] != "/") do i -= 1 end + if i == 0 return "/" + return path[0..i] +end + +fn cmd_cd(words) do + const arg = if words:len() > 1 words[1] else "/" + const target = if arg == ".." parent_of(wd.path) else abspath(arg) + if target == "/proc" or target == "/bin" or fs:is_dir(target) do wd.path = target end + else do puts("cd: #{arg}: not a directory\n") end +end + +fn cmd_pwd() puts("#{wd.path}\n") + +fn cmd_ls(words) do + const target = if words:len() > 1 abspath(words[1]) else wd.path + if vfs_owns(target) do vfs_ls(target) return :nil end + const n = fs:ls(target) + # the virtual mounts arent real dir entries, overlay them on the root listing + if target == "/" do puts(" bin/\n proc/\n") end + else if n == 0 do puts(" (empty)\n") end +end + +fn cmd_mkdir(words) do + if words:len() < 2 do puts("usage: mkdir \n") return :nil end + fs:mkdir(abspath(words[1])) +end + fn cmd_write(line) do const a = arg_name(line, 6) if a.name:len() == 0 do puts("usage: write \n") return :nil end - fs:write(a.name, line[a.rest..]) + fs:write(abspath(a.name), line[a.rest..]) end fn cmd_cat(line) do const a = arg_name(line, 4) if a.name:len() == 0 do puts("usage: cat \n") return :nil end - fs:cat(a.name) + const p = abspath(a.name) + if vfs_owns(p) do vfs_cat(p) return :nil end + fs:cat(p) end fn cmd_rm(line) do const a = arg_name(line, 3) if a.name:len() == 0 do puts("usage: rm \n") return :nil end - fs:rm(a.name) + fs:rm(abspath(a.name)) end fn zoom_by(delta) do @@ -136,12 +213,18 @@ fn cmd_uptime() puts("#{math.floor(uptime() / 100)}s (#{uptime()} ticks)\n") fn cmd_ps() puts("#{proc_count()} process(es) running\n") fn run(line) do + if editor.active do editor_line(line) return :nil end if line:trim():len() == 0 do puts("% ") return :nil end const words = line:split(" ") const cmd = words[0] + if cmd == "edit" do cmd_edit(line) return :nil end if cmd == "run" do if words:len() <= 1 do list_progs() puts("% ") return :nil end - if run_prog(words[1]) == :true return :nil + const prog = words[1] + # everything after "run " is the programs argument string + const start = 4 + prog:len() + 1 + const arg = if line:len() > start line[start..] else "" + if run_prog(prog, arg) == :true return :nil puts("% ") return :nil end @@ -154,10 +237,13 @@ fn run(line) do | "ps" => cmd_ps() | "zoom" => cmd_zoom(words) | "mkfs" => fs:format() - | "ls" => fs:ls() + | "ls" => cmd_ls(words) | "cat" => cmd_cat(line) | "write" => cmd_write(line) | "rm" => cmd_rm(line) + | "mkdir" => cmd_mkdir(words) + | "cd" => cmd_cd(words) + | "pwd" => cmd_pwd() | "echo" => if line:len() > 5 puts("#{line[5..]}\n") else puts("\n") | _ => puts("unknown command: #{cmd}\n") puts("% ") -- cgit v1.3