From e2331b67ff34417b6410508d74ec26a14e7fdb95 Mon Sep 17 00:00:00 2001 From: payonel Date: Sat, 16 Jul 2016 01:08:31 -0700 Subject: [PATCH] improvements to guid, devfs, cat, cp, and system error clarity renaming guid to uuid and removing useless method toHex adding text read and writer, compare to c++ stdlib stringstream. needed for advanced devfs fix globbing with relative paths and . and .. in path moving install confirmation before calling .install fix cp: cp -r . /another/path (should copy contents of current dir) fix cat when stdin is missing or closed improved devfs supporting custom dir handlers for dynamic file listing other non functional changes to clean up code and improved error messages --- .../opencomputers/loot/openos/bin/cat.lua | 9 +- .../opencomputers/loot/openos/bin/cp.lua | 12 +- .../opencomputers/loot/openos/bin/mkdir.lua | 2 +- .../opencomputers/loot/openos/bin/mktmp.lua | 6 +- .../loot/openos/boot/10_devfs.lua | 3 +- .../opencomputers/loot/openos/lib/devfs.lua | 343 +++++++++++++----- .../loot/openos/lib/filesystem.lua | 13 +- .../opencomputers/loot/openos/lib/guid.lua | 47 --- .../opencomputers/loot/openos/lib/sh.lua | 3 +- .../opencomputers/loot/openos/lib/term.lua | 9 +- .../opencomputers/loot/openos/lib/text.lua | 89 +++++ .../openos/lib/tools/devfs/eeprom-data.lua | 19 + .../loot/openos/lib/tools/devfs/eeprom.lua | 19 + .../loot/openos/lib/tools/devfs/null.lua | 12 + .../loot/openos/lib/tools/devfs/random.lua | 21 ++ .../loot/openos/lib/tools/install_basics.lua | 12 +- .../loot/openos/lib/tools/install_utils.lua | 8 +- .../opencomputers/loot/openos/lib/uuid.lua | 22 ++ .../opencomputers/loot/openos/usr/man/install | 4 +- 19 files changed, 491 insertions(+), 162 deletions(-) delete mode 100644 src/main/resources/assets/opencomputers/loot/openos/lib/guid.lua create mode 100644 src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom-data.lua create mode 100644 src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom.lua create mode 100644 src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/null.lua create mode 100644 src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/random.lua create mode 100644 src/main/resources/assets/opencomputers/loot/openos/lib/uuid.lua diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua index 8772e44e4..6a943ab78 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua @@ -13,9 +13,14 @@ for i = 1, #args do io.stderr:write(string.format('cat %s: Is a directory\n', arg)) ec = 1 else - local file, reason = args[i] == "-" and io.stdin or io.open(shell.resolve(args[i])) + local file, reason + if args[i] == "-" then + file, reason = io.stdin, "missing stdin" + else + file, reason = io.open(shell.resolve(args[i])) + end if not file then - io.stderr:write(string.format("cat: %s: %s\n",args[i],tostring(reason))) + io.stderr:write(string.format("cat: %s: %s\n", args[i], tostring(reason))) ec = 1 else repeat diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/cp.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/cp.lua index 82be2fc9c..cd4c8401c 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/cp.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/cp.lua @@ -148,12 +148,14 @@ end local to = shell.resolve(args[#args]) for i = 1, #args - 1 do - local fromPath, cuts = args[i]:gsub("(/%.%.?)$", "%1") - fromPath = shell.resolve(fromPath) + local arg = args[i] + local fromPath = shell.resolve(arg) + -- a "contents of" copy is where src path ends in . or .. + -- a source path ending with . is not sufficient - could be the source filename + local contents_of = arg:match("%.$") and not fromPath:match("%.$") local toPath = to - -- fromPath ending with /. indicates copying the contents of fromPath - -- in which case (cuts>0) we do not append fromPath name to toPath - if cuts == 0 and fs.isDirectory(toPath) then + -- we do not append fromPath name to toPath in case of contents_of copy + if not contents_of and fs.isDirectory(toPath) then toPath = fs.concat(toPath, fs.name(fromPath)) end result, reason = recurse(fromPath, toPath) diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/mkdir.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/mkdir.lua index 49fb40bc0..3e8376327 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/mkdir.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/mkdir.lua @@ -19,7 +19,7 @@ for i = 1, #args do reason = "unknown reason" end end - io.stderr:write(path .. ": " .. reason .. "\n") + io.stderr:write("mkdir: cannot create directory '" .. tostring(args[i]) .. "': " .. reason .. "\n") ec = 1 end end diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/mktmp.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/mktmp.lua index d01ab987c..7e6327f3c 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/mktmp.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/mktmp.lua @@ -1,12 +1,12 @@ local fs = require("filesystem") -local guid = require("guid") +local uuid = require("uuid") local shell = require("shell") local sh = require("sh") local touch = loadfile(shell.resolve("touch", "lua")) local mkdir = loadfile(shell.resolve("mkdir", "lua")) -if not guid or not touch then +if not uuid or not touch then local errorMessage = "missing tools for mktmp" io.stderr:write(errorMessage .. '\n') return false, errorMessage @@ -58,7 +58,7 @@ if not fs.exists(prefix) then end while true do - local tmp = prefix .. guid.next() + local tmp = prefix .. uuid.next() if not fs.exists(tmp) then local ok, reason diff --git a/src/main/resources/assets/opencomputers/loot/openos/boot/10_devfs.lua b/src/main/resources/assets/opencomputers/loot/openos/boot/10_devfs.lua index 0da8de199..3cb2c8604 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/boot/10_devfs.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/boot/10_devfs.lua @@ -1,6 +1,7 @@ require("filesystem").mount( setmetatable({ - isReadOnly = function()return false end + isReadOnly = function()return false end, + address = require("uuid").next() }, { __index=function(tbl,key)return require("devfs")[key]end diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/devfs.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/devfs.lua index bee88b701..8848173cf 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/devfs.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/devfs.lua @@ -1,111 +1,292 @@ local fs = require("filesystem") +local comp = require("component") -local proxy = {points={},address=require("guid").next()} +local function new_node(parent, name, is_dir, proxy) + local node = {parent=parent, name=name, is_dir=is_dir, proxy=proxy} + if not proxy then + node.children = {} + end + return node +end -local nop = function()end +local function new_devfs_dir(name) + local sys = {} + sys.mtab = new_node(nil, name or "/", true) -function proxy.getLabel() + -- returns: dir, point or path + -- node (table): the handler responsible for the path + -- this is essentially the device filesystem that is registered for the given path + -- point (string): the point name (like a file name) + function sys.findNode(path, create) + checkArg(1, path, "string") + local segments = fs.segments(path) + local node = sys.mtab + while #segments > 0 do + local name = table.remove(segments, 1) + local prev_path = path + path = table.concat(segments, "/") + + if not node.children[name] then + if not create then + path = prev_path + break + end + node.children[name] = new_node(node, name, true, false) + end + + node = node.children[name] + + if node.proxy then -- if there is a proxy handler we stop searching here + break + end + end + + -- only dirs can have trailing path + -- trailing path on a dev point (file) not allowed + if path == "" or node.is_dir and node.proxy then + return node, path + end + end + + function sys.invoke(method, path, ...) + local node, rest = sys.findNode(path) + if not node or -- not found + rest == "" and node.is_dir or -- path is dir + not node.proxy[method] then -- optional method + return 0 + end + -- proxy could be a file, which doesn't take an argument, but it can be ignored if passed + return node.proxy[method](rest) + end + + function sys.size(path) + return sys.invoke("size", path) + end + + function sys.lastModified(path) + return sys.invoke("lastModified", path) + end + + function sys.isDirectory(path) + local node, rest = sys.findNode(path) + if not node then + return + end + + if rest == "" then + return node.is_dir + elseif node.proxy then + return node.proxy.isDirectory(rest) + end + end + + function sys.open(path, mode) + checkArg(1, path, "string") + checkArg(2, mode, "string", "nil") + + if not sys.exists(path) then + return nil, path.." file not found" + elseif sys.isDirectory(path) then + return nil, path.." is a directory" + end + + mode = mode or "r" + -- everything at this level should be a binary open + mode = mode:gsub("b", "") + + if not ({a=true,w=true,r=true})[mode] then + return nil, "invalid mode" + end + + local node, rest = sys.findNode(path) + -- there must be a node, else exists would have failed + + local args = {} + if rest ~= "" then + -- having more rest means we expect the proxy fs to open the point + args[1] = rest + end + args[#args+1] = mode + + return node.proxy.open(table.unpack(args)) + end + + function sys.list(path) + local node, rest = sys.findNode(path) + if not node or (rest ~= "" and not node.is_dir) then-- not found + return {} + elseif rest == "" and not node.is_dir then -- path is file + return {path} + elseif node.proxy then + -- proxy could be a file, which doesn't take an argument, but it can be ignored if passed + return node.proxy.list(rest) + end + + -- rest == "" and node.is_dir + local keys = {} + for k in pairs(node.children) do + table.insert(keys, k) + end + return keys + end + + function sys.remove(path) + checkArg(1, path, "string") + + if path == "" then + return nil, "no such file or directory" + end + + if not sys.exists(path) then + return nil, path.." file not found" + end + + local node, rest = sys.findNode(path) + + if rest ~= "" then -- if rest is not resolved, this isn't our path + return node.proxy.remove(rest) + end + + node.parent.children[node.name] = nil + end + + function sys.exists(path) + checkArg(1, path, "string") + local node, rest = sys.findNode(path) + + if not node then + return false + elseif rest == "" then + return true + else + return node.proxy.exists(rest) + end + end + + function sys.create(path, handler) + if sys.exists(path) then + return nil, "path already exists" + end + + local segments = fs.segments(path) + local target = table.remove(segments) + path = table.concat(segments, "/") + + if not target or target == "" then + return nil, "missing argument" + end + + local node, rest = sys.findNode(path, true) + if rest ~= "" then + return node.proxy.create(rest, handler) + end + node.children[target] = new_node(node, target, not not handler.list, handler) + return true + end + + return sys +end + +local devfs = new_devfs_dir() + +local bfd = "bad file descriptor" + +function devfs.getLabel() return "devfs" end -function proxy.setLabel(value) +function devfs.setLabel(value) error("drive does not support labeling") end -function proxy.spaceTotal() +function devfs.spaceTotal() return 0 end -function proxy.spaceUsed() +function devfs.spaceUsed() return 0 end -function proxy.exists(path) - return not not proxy.points[path] +function devfs.makeDirectory(path) + return false, "to create dirs in devfs use devfs.create" end -function proxy.size(path) - return 0 -end - -function proxy.isDirectory(path) - return false -end - -function proxy.lastModified(path) - return fs.lastModified("/dev/") -end - -function proxy.list() - local keys = {} - for k,v in pairs(proxy.points) do - table.insert(keys, k) - end - return keys -end - -function proxy.makeDirectory(path) - return false -end - -function proxy.remove(path) - if not proxy.exists(path) then return false end - proxy.points[path] = nil - return true -end - -function proxy.rename(from, to) - return false -end - -proxy.close = nop - -function proxy.open(path, mode) - checkArg(1, path, "string") - - local handle = proxy.points[path] - if not handle then return nil, "device point [" .. path .. "] does not exist" end - - local msg = "device point [" .. path .. "] cannot be opened for " - - if mode == "r" then - if not handle.read then - return nil, msg .. "read" - end - else - if not handle.write then - return nil, msg .. "write" - end - end - - return handle -end - -function proxy.read(h,...) +function devfs.read(h,...) + if not h.read then return nil, bfd end return h:read(...) end -function proxy.seek(h,...) +function devfs.seek(h,...) + if not h.seek then return nil, bfd end return h:seek(...) end -function proxy.write(h,...) +function devfs.write(h,...) + if not h.write then return nil, bfd end return h:write(...) end -function proxy.create(path, handle) - handle.close = handle.close or nop - proxy.points[path] = handle - return true +function devfs.close(h, ...) + if not h.close then return nil, bfd end + return h:close(...) end -proxy.create("null", {write = nop}) -proxy.create("random", {read = function(_,n) - local chars = {} - for i=1,n do - table.insert(chars,string.char(math.random(0,255))) - end - return table.concat(chars) -end}) +-- devfs.create creates a new dev point at path +-- devfs is mounted to /sys by default, and /dev is a symlink to /sys/dev. If you want a devfs point to show up in /dev, specify a path here as "/dev/your_path") +-- the handler can be a single file dev file (called a point), or a devfs dir [which allows it to list its own dynamic list of points and dirs] +-- note: devfs dirs that list their own child dirs will have to handle directory queries on their own, such as list() and open(path, mode) -return proxy +-- A handler represents a directory IF it defines list(), which returns a string array of the point names +-- a directory handler acts like simplified filesystem of its own. +-- note: that when creating new devfs points or dirs, devfs.create will not traverse into dynamic directory children of dev mount points +-- Meaning, if you create a devfs dir, which returns dirs children of its own, devfs.create does not support creating dev points +-- on those children + +-- see new_devfs_dir() -- it might work for you, /dev uses it + +-- Also note, your own devfs dirs may implement open() however they like -- devfs points' open() is called by the devfs library but dynamic +-- dir act as their own library for their own points + +-- ### devfs point methods ### +-- Required + -- open(mode: string []) file: returns new file handle for point (see "devfs point handle methods") +-- Optional + -- size(path) number + +-- ### devfs point handle instance methods ### +-- Required + -- + technicaly, one of the following is not required when the mode is for the other (e.g. no read when in write mode) + -- write(self, value, ...) boolean: writes each value (params list) and returns success + -- read(self, n: number) string: return string of n bytes, nil when no more bytes available +-- Optional + -- seek(self, whence [string], offset [number]) number: move file handle from whence by offset, return offset result + -- close(self) boolean: close the file handle. Note that if your open method allocated resources, you'll need to release them in close + +-- ### devfs dir methods ### +-- Required + -- list() string[]: return list of child point names + -- if you use new_devfs_dir, set metatable on .points with __pairs and __index if you want a dynamic list of files + -- open(path, mode) file (table): return a file handle to path (path is relative) + -- it would be nice to make open() optional, but devfs doesn't know where you might store your point handlers, if you even have any +-- Optional + -- size(path) number + -- lastModified(path) number + -- isDirectory(path) boolean -- default returns false. Having dynamic dirs is considered advanced + -- remove(path) boolean + -- rename(path) boolean + -- exists(path) boolean -- default checks path against list() results + +-- /dev is a special handler + +local function devfs_load(key) + return require("tools/devfs/" .. key) +end + +devfs.create("null", devfs_load("null")) +devfs.create("random", devfs_load("random")) +if comp.isAvailable("eeprom") then + devfs.create("eeprom", devfs_load("eeprom")) + devfs.create("eeprom-data", devfs_load("eeprom-data")) +end + +return devfs diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua index ea6896f67..f46c8212a 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua @@ -112,9 +112,7 @@ function filesystem.setAutorunEnabled(value) saveConfig() end -function filesystem.segments(path) - return segments(path) -end +filesystem.segments = segments function filesystem.canonical(path) local result = table.concat(segments(path), "/") @@ -367,7 +365,11 @@ function filesystem.makeDirectory(path) end local node, rest = findNode(path) if node.fs and rest then - return node.fs.makeDirectory(rest) + local success, reason = node.fs.makeDirectory(rest) + if not success and not reason and node.fs.isReadOnly() then + reason = "filesystem is readonly" + end + return success, reason end if node.fs then return nil, "virtual directory with that name already exists" @@ -502,11 +504,12 @@ function filesystem.open(path, mode) checkArg(1, path, "string") mode = tostring(mode or "r") checkArg(2, mode, "string") + assert(({r=true, rb=true, w=true, wb=true, a=true, ab=true})[mode], "bad argument #2 (r[b], w[b] or a[b] expected, got " .. mode .. ")") local node, rest = findNode(path) - if not node.fs or not rest then + if not node.fs or not rest or (({r=true,rb=true})[mode] and not node.fs.exists(rest)) then return nil, "file not found" end diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/guid.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/guid.lua deleted file mode 100644 index 13cfc7217..000000000 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/guid.lua +++ /dev/null @@ -1,47 +0,0 @@ -local guid = {} - -function guid.toHex(n) - if type(n) ~= 'number' then - return nil, string.format("toHex only converts numbers to strings, %s is not a string, but a %s", tostring(n), type(n)) - end - if n == 0 then - return '0' - end - - local hexchars = "0123456789abcdef" - local result = "" - local prefix = "" -- maybe later allow for arg to request 0x prefix - if n < 0 then - prefix = "-" - n = -n - end - - while n > 0 do - local next = math.floor(n % 16) + 1 -- lua has 1 based array indices - n = math.floor(n / 16) - result = hexchars:sub(next, next) .. result - end - - return prefix .. result -end - -function guid.next() - -- e.g. 3c44c8a9-0613-46a2-ad33-97b6ba2e9d9a - -- 8-4-4-4-12 - local sets = {8, 4, 4, 4, 12} - local result = "" - - local i - for _,set in ipairs(sets) do - if result:len() > 0 then - result = result .. "-" - end - for i = 1,set do - result = result .. guid.toHex(math.random(0, 15)) - end - end - - return result -end - -return guid diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/sh.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/sh.lua index 159e9072d..bb90f56d4 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/sh.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/sh.lua @@ -454,7 +454,7 @@ function --[[@delayloaded-start@]] sh.internal.glob(glob_pattern) local function magical(s) for _,glob_rule in ipairs(sh.internal.globbers) do - if s:match("[^%%]-"..text.escapeMagic(glob_rule[2])) then + if (" "..s):match("[^%%]"..text.escapeMagic(glob_rule[2])) then return true end end @@ -464,7 +464,6 @@ function --[[@delayloaded-start@]] sh.internal.glob(glob_pattern) local root = is_abs and '' or shell.getWorkingDirectory():gsub("([^/])$","%1/") local paths = {is_abs and "/" or ''} local relative_separator = '' - for i,segment in ipairs(segments) do local enclosed_pattern = string.format("^(%s)/?$", segment) local next_paths = {} diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua index fed3a783c..35770953d 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua @@ -243,14 +243,17 @@ function term.readKeyboard(ops) end while true do - local killed, name, address, char, code = term.internal.pull(input) + local ok, name, address, char, code = term.internal.pull(input) + if not term.isAvailable() then + return + end -- we have to keep checking what kb is active in case it is switching during use -- we could have multiple screens, each with keyboards active local main_kb = term.keyboard(w) local main_sc = term.screen(w) - local c = nil + local c local backup_cache = hints.cache - if name == "interrupted" or name == "term_unavailable" then + if name == "interrupted" then draw("^C\n",true) return "" elseif address == main_kb or address == main_sc then diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/text.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/text.lua index 3556923b6..353efb132 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/text.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/text.lua @@ -288,4 +288,93 @@ function --[[@delayloaded-start@]] text.internal.normalize(words, omitQuotes) return norms end --[[@delayloaded-end@]] +function --[[@delayloaded-start@]] text.internal.seeker(handle, whence, to) + if not handle.txt then + return nil, "bad file descriptor" + end + to = to or 0 + if whence == "cur" then + handle.offset = handle.offset + to + elseif whence == "set" then + handle.offset = to + elseif whence == "end" then + handle.offset = handle.len + to + end + handle.offset = math.max(0, math.min(handle.offset, handle.len)) + return handle.offset +end --[[@delayloaded-end@]] + +function --[[@delayloaded-start@]] text.internal.reader(txt) + checkArg(1, txt, "string") + local reader = + { + txt = txt, + len = unicode.len(txt), + offset = 0, + read = function(_, n) + checkArg(1, n, "number") + if not _.txt then + return nil, "bad file descriptor" + end + if _.offset >= _.len then + return nil + end + local last_offset = _.offset + _:seek("cur", n) + local next = unicode.sub(_.txt, last_offset + 1, _.offset) + return next + end, + seek = text.internal.seeker, + close = function(_) + if not _.txt then + return nil, "bad file descriptor" + end + _.txt = nil + return true + end, + } + + return reader +end --[[@delayloaded-end@]] + +function --[[@delayloaded-start@]] text.internal.writer(ostream, append_txt) + if type(ostream) == "table" then + local mt = getmetatable(ostream) or {} + checkArg(1, mt.__call, "function") + end + checkArg(1, ostream, "function", "table") + checkArg(2, append_txt, "string", "nil") + local writer = + { + txt = "", + offset = 0, + len = 0, + write = function(_, ...) + if not _.txt then + return nil, "bad file descriptor" + end + local pre, vs, pos = unicode.sub(_.txt, 1, _.offset), {}, unicode.sub(_.txt, _.offset + 1) + for i,v in ipairs({...}) do + table.insert(vs, v) + end + vs = table.concat(vs) + _:seek("cur", unicode.len(vs)) + _.txt = pre .. vs .. pos + _.len = unicode.len(_.txt) + return true + end, + seek = text.internal.seeker, + close = function(_) + if not _.txt then + return nil, "bad file descriptor" + end + ostream((append_txt or "") .. _.txt) + _.txt = nil + return true + end, + } + + return writer +end --[[@delayloaded-end@]] + return text, local_env diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom-data.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom-data.lua new file mode 100644 index 000000000..2aea1a0ef --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom-data.lua @@ -0,0 +1,19 @@ +local comp = require("component") +local text = require("text") + +if not comp.isAvailable("eeprom") then + return nil +end + +return +{ + open = function(mode) + if ({r=true, rb=true})[mode] then + return text.internal.reader(comp.eeprom.getData()) + end + return text.internal.writer(comp.eeprom.setData, ({a=true,ab=true})[mode] and comp.eeprom.getData()) + end, + size = function() + return string.len(comp.eeprom.getData()) + end +} diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom.lua new file mode 100644 index 000000000..dbc9ceafb --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/eeprom.lua @@ -0,0 +1,19 @@ +local comp = require("component") +local text = require("text") + +if not comp.isAvailable("eeprom") then + return nil +end + +return +{ + open = function(mode) + if ({r=true, rb=true})[mode] then + return text.internal.reader(comp.eeprom.get()) + end + return text.internal.writer(comp.eeprom.set, ({a=true,ab=true})[mode] and comp.eeprom.get()) + end, + size = function() + return string.len(comp.eeprom.get()) + end +} diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/null.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/null.lua new file mode 100644 index 000000000..c3710917a --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/null.lua @@ -0,0 +1,12 @@ +return +{ + open = function(mode) + if not mode or not mode:match("[wa]") then + return nil, "write only" + end + return + { + write = function() end + } + end +} diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/random.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/random.lua new file mode 100644 index 000000000..15c08617a --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/devfs/random.lua @@ -0,0 +1,21 @@ +return +{ + open = function(mode) + if mode and not mode:match("r") then + return nil, "read only" + end + return + { + read = function(self, n) + local chars = {} + for i=1,n do + table.insert(chars,string.char(math.random(0,255))) + end + return table.concat(chars) + end + } + end, + size = function() + return math.huge + end +} diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_basics.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_basics.lua index eaa2c8591..bd4188080 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_basics.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_basics.lua @@ -171,16 +171,11 @@ options.setboot = source.prop.setboot and not options.nosetboot options.reboot = source.prop.reboot and not options.noreboot options.source_dir = fs.canonical(source.prop.fromDir or options.fromDir or "") .. '/.' -local installer_path = options.source_root .. "/.install" -if fs.exists(installer_path) then - os.exit(loadfile("/lib/tools/install_utils.lua", "bt", _G)('install', options)) -end - local cp_args = { "-vrx" .. (options.update and "ui" or ""), options.source_root .. options.source_dir, - options.target_root .. options.target_dir + options.target_root:gsub("//","/") .. options.target_dir } local source_display = (source.prop or {}).label or source.dev.getLabel() or source.path @@ -194,6 +189,11 @@ if not ((io.read() or "n").."y"):match("^%s*[Yy]") then os.exit() end +local installer_path = options.source_root .. "/.install" +if fs.exists(installer_path) then + os.exit(loadfile("/lib/tools/install_utils.lua", "bt", _G)('install', options)) +end + return { setlabel = options.setlabel, diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_utils.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_utils.lua index cbaae9a70..af48bef83 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_utils.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tools/install_utils.lua @@ -41,18 +41,18 @@ end if cmd == 'select' then if #options.sources == 0 then if options.source_label then - io.stderr:write("No install source matched given label: " .. options.source_label .. '\n') + io.stderr:write("Nothing to install labeled: " .. options.source_label .. '\n') elseif options.from then - io.stderr:write("No install source found: " .. options.from .. '\n') + io.stderr:write("Nothing to install from: " .. options.from .. '\n') else - io.stderr:write("Could not find any available installations\n") + io.stderr:write("Nothing to install\n") end os.exit(1) end if #options.targets == 0 then if options.to then - io.stderr:write("No such filesystem to install to: " .. options.to .. '\n') + io.stderr:write("No such target to install to: " .. options.to .. '\n') else io.stderr:write("No writable disks found, aborting\n") end diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/uuid.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/uuid.lua new file mode 100644 index 000000000..ffee13682 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/uuid.lua @@ -0,0 +1,22 @@ +local uuid = {} + +function uuid.next() + -- e.g. 3c44c8a9-0613-46a2-ad33-97b6ba2e9d9a + -- 8-4-4-4-12 (halved sizes because bytes make hex pairs) + local sets = {4, 2, 2, 2, 6} + local result = "" + + local i + for _,set in ipairs(sets) do + if result:len() > 0 then + result = result .. "-" + end + for i = 1,set do + result = result .. string.format("%02x", math.random(0, 255)) + end + end + + return result +end + +return uuid diff --git a/src/main/resources/assets/opencomputers/loot/openos/usr/man/install b/src/main/resources/assets/opencomputers/loot/openos/usr/man/install index 45c3ab25a..03f89af0a 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/usr/man/install +++ b/src/main/resources/assets/opencomputers/loot/openos/usr/man/install @@ -9,10 +9,10 @@ DESCRIPTION OPTIONS --from=ADDR - Specifies the source filesystem or its root path. ADDR can be the device guid or a directory path. If this is a directory path, it represents a root path to install from. This option can also be used to specify source paths that would otherwise be ignored, those being devfs, tmpfs, and the rootfs. e.g. --from=/tmp . Note that if both --from and a [name] is given, install expects the source path to have a .prop defining the same name. See .prop for more details. + Specifies the source filesystem or its root path. ADDR can be the device uuid or a directory path. If this is a directory path, it represents a root path to install from. This option can also be used to specify source paths that would otherwise be ignored, those being devfs, tmpfs, and the rootfs. e.g. --from=/tmp . Note that if both --from and a [name] is given, install expects the source path to have a .prop defining the same name. See .prop for more details. --to=ADDR - Same as --from but specifies the target filesystem by guid or its root path. This option can also be used to specify filesystems that are otherwise ignored including tmpfs. i.e. --to=ADDR where ADDR matches the tmpfs device address or its mount point path. e.g. --to=/tmp + Same as --from but specifies the target filesystem by uuid or its root path. This option can also be used to specify filesystems that are otherwise ignored including tmpfs. i.e. --to=ADDR where ADDR matches the tmpfs device address or its mount point path. e.g. --to=/tmp --fromDir=PATH Install PATH from source. PATH is relative to the root of the source filesystem or path given by --from. The default is .