2.21.2025 (BETA)

This commit is contained in:
Jase 2025-02-21 00:33:21 -05:00
commit ce60ed8a0b
20 changed files with 1409 additions and 0 deletions

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2025 Jase Williams
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# BananaOS
opencomputers test

9
test/TODO Normal file
View File

@ -0,0 +1,9 @@
- Filesystem
Mounts and virtual mounts (ie /tmp, /dev)
Protected paths
- Package
Error handling
Paths
- I/O

227
test/bin/openfetch.lua Normal file
View File

@ -0,0 +1,227 @@
-- openfetch 1.4 | by ethernalsteve & Bs0Dd
local component = require("component")
local computer = require("computer")
local fs = require("filesystem")
local gpu = component.gpu
local logos = {
{
" %%%%(///////(%%% ",
" %% (///%%%/(%%%%% ",
" %% (///%%%/(%%%%% ",
" %% (///////(%%%%% ",
" %%%%%%%%%%%%%%%%%%% ",
" %%%%%%%%%%%%%%%%%%% ",
" %% %% ",
" %% %% ",
" %%%%%%%%%%%%%%%%%%% ",
" %%%%%%%%%%%%%%%%% "
},
{
" %%%%%(///////////////(%%%% ",
" %%%###(//////%%%%%%///(%%%%%%% ",
" %%%###(//////%%%%%%///(%%%%%%% ",
" %%%###(//////%%%%%%///(%%%%%%% ",
" %%%###(//////%%%%%%///(%%%%%%% ",
" %%%###(///////////////(%%%%%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
" %%%((((((((((((((((((((((((%%% ",
" %%%((((((((((((((((((((((((%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
" %%% %%% ",
" %%%////////////////////////%%% ",
" %%% %%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%% "
},
{
" %%%%%%%%%%(///////////////////////(%%%%%%% ",
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%% ",
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
" %%%%%%#####(///////////%%%%%%%/////(%%%%%%%%%% ",
" %%%%%%#####(///////////////////////(%%%%%%%%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
" %%%%%%((((((((((((((((((((((((((((((((((%%%%%% ",
" %%%%%%((((((((((((((((((((((((((((((((((%%%%%% ",
" %%%%%%((((((((((((((((((((((((((((((((((%%%%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
" %%%%%% %%%%%% ",
" %%%%%% %%%%%% ",
" %%%%%% %%%%%% ",
" %%%%%%//////////////////////////////////%%%%%% ",
" %%%%%% %%%%%% ",
" %%%%%% %%%%%% ",
" %%%%%% %%%%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
}
}
local w, h = gpu.maxResolution()
local devs = component.computer.getDeviceInfo()
local gpuInfoStr
local function getGPUTier()
local dp = gpu.maxDepth()
if dp == 8 then
return 3
elseif dp == 4 then
return 2
else
return 1
end
end
local function getModel(desc)
local name
for _, dev in pairs(devs) do
if dev.description == desc then
name = dev.product
break
end
end
return name
end
local OS = "Unknown"
if fs.exists("OS.lua") then
OS = "MineOS"
elseif fs.exists("/lib/core") then
OS = "OpenOS"
elseif fs.exists("/root") then
OS = "Plan9k"
elseif fs.exists("/etc/system/") then
OS = "BananaOS"
end
local function getParsedUptime()
local seconds, minutes, hours = math.floor(computer.uptime()), 0, 0
local time = ""
if seconds >= 60 then
minutes = math.floor(seconds / 60)
seconds = seconds % 60
end
if minutes >= 60 then
hours = math.floor(minutes / 60)
minutes = minutes % 60
end
if getGPUTier() == 1 then
time = time .. string.format("%02d:%02d:%02d", hours, minutes, seconds)
else
if hours == 1 then time = hours .. " hour, "
elseif hours >= 2 then time = hours .. " hours, "
end
if minutes == 1 then time = time .. minutes .. " min, "
elseif minutes >= 2 then time = time .. minutes .. " mins, "
end
time = time .. seconds .. " sec"
end
return time
end
local logo = logos[getGPUTier()]
local function addCharacteristics()
local cpu, apu = getModel("CPU"), getModel("APU")
gpuInfoStr = 8
logo[2] = logo[2] .. "|OS:|" .. OS
logo[3] = logo[3] .. "|Uptime:|" .. getParsedUptime()
logo[4] = logo[4] .. "|Architecture:|" .. _VERSION
logo[5] = logo[5] .. "|Resolution:|" .. math.floor(w) .. "x" .. math.floor(h)
logo[6] = logo[6] .. "|Terminal:|" .. getModel("Text buffer")
if cpu ~= nil then logo[7] = logo[7] .. "|CPU:|" .. cpu:sub(0,11) .. ' (' .. cpu:match('%d') .. ' Tier)'
elseif apu ~= nil then logo[7] = logo[7] .. "|APU:|" .. apu:sub(0,11) .. ' (' .. apu:match('%d') .. ' Tier)' end
for _, dev in pairs(devs) do
if dev.description == "Graphics controller" then
logo[gpuInfoStr] = logo[gpuInfoStr] .. "|GPU:|" .. dev.product .. ' (' .. dev.product:match('%d') .. ' Tier)'
gpuInfoStr = gpuInfoStr + 1
end
end
logo[gpuInfoStr] = logo[gpuInfoStr] .. "|Memory:|" .. math.floor(computer.totalMemory() / 1024 - computer.freeMemory() / 1024) .. " KB / " .. math.floor(computer.totalMemory() / 1024) .. " KB"
end
local function drawPalette()
local palette = {{0x000000, 0x333333}, {0xCC0000, 0xFF0000}, {0x00CC00, 0x00FF00}, {0xCCCC00, 0xFFFF00},
{0x0000CC, 0x0000FF}, {0xCC00CC, 0xFF00FF}, {0x00CCCC, 0x00FFFF}, {0xCCCCCC, 0xFFFFFF}}
local cur = #logo[1] + 2
for _, color in pairs(palette) do
gpu.setForeground(color[1])
gpu.set(cur, gpuInfoStr + 2, "███")
gpu.setForeground(color[2])
gpu.set(cur, gpuInfoStr + 3, "███")
cur = cur + 3
end
end
gpu.setResolution(w, h)
addCharacteristics()
gpu.setBackground(0x000000)
gpu.fill(1, 1, w, h, " ")
for i = 1, #logo do
local logoLine, tmp, f = {}, {}, false
logo[i]:gsub(".", function(c) table.insert(logoLine, c) end)
for ii = 1, #logoLine do
if f then
if string.match(logoLine[ii], "|") then
f = false
else
if string.match(logoLine[ii], ":") then
gpu.setForeground(0xffffff)
elseif OS == "MineOS" then
gpu.setForeground(0x32e3de)
elseif OS == "OpenOS" then
gpu.setForeground(0x30ff80)
elseif OS == "Plan9k" then
gpu.setForeground(0xff0000)
elseif OS == "BananaOS" then
gpu.setForeground(0xffff00)
end
gpu.set(ii, i, logoLine[ii])
end
else
if logoLine[ii] == "%" then
if OS == "MineOS" then
gpu.setForeground(0x35ffff)
elseif OS == "OpenOS" then
gpu.setForeground(0x228822)
elseif OS == "Plan9k" then
gpu.setForeground(0xff0000)
elseif OS == "BananaOS" then
gpu.setForeground(0xcccc00)
end
gpu.set(ii, i, logoLine[ii])
elseif logoLine[ii] == "/" then
gpu.setForeground(0xfffafa)
gpu.set(ii, i, logoLine[ii])
elseif logoLine[ii] == "#" then
gpu.setForeground(0x585858)
gpu.set(ii, i, logoLine[ii])
elseif logoLine[ii] == "(" then
gpu.setForeground(0xc0c0c0)
gpu.set(ii, i, logoLine[ii])
elseif string.match(logoLine[ii], "|") then
f = true
else
gpu.setForeground(0xffffff)
gpu.set(ii, i, logoLine[ii])
end
end
end
end
drawPalette()
if OS == "MineOS" then
gpu.set(1, #logo + 2 > 14 and #logo + 2 or 14, 'Press any key to exit.')
local evtype
while evtype ~= 'key_down' do
evtype = computer.pullSignal()
end
else
--require("term").setCursor(1, #logo + 2 > 14 and #logo + 2 or 14)
end

View File

@ -0,0 +1,49 @@
local _, _, status, _ = ...
status(" *- Implementing component functions")
function package.loaded.component.isAvailable(componentType)
if component[componentType] then
return true
end
return false
end
function package.loaded.component.get(address, componentType)
local comp = package.loaded.component.list(componentType)
for a,_ in comp do
if a == address then
return a
else
local s,e = string.find(a,address)
if s == 1 then
return a
end
end
end
return nil, "no such component"
end
function package.loaded.component.getPrimary(componentType)
local prim = component[componentType]
if not prim then
error(string.format("no primary '%s' available", componentType))
end
return prim
end
function package.loaded.component.setPrimary(componentType, address)
if componentType == "filesystem" then
return
end
address = package.loaded.component.get(address:sub(1,5), componentType) -- don't sub
package.loaded.component[componentType] = package.loaded.component.proxy(address)
end
local components = package.loaded.component.list()
status(" *- Setting primary components")
for address, componentType in components do
package.loaded.component.setPrimary(componentType,address)
end

12
test/etc/motd Normal file
View File

@ -0,0 +1,12 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ Welcome to BANANA OS. @
@@@@@@@@@@@@@@@@@@@@@@@@@@@
* The world's greatest OpenComputers
operating system. No batteries included
* It is also in beta.
To get started, do something.

189
test/etc/system/boot.lua Normal file
View File

@ -0,0 +1,189 @@
local loadfile, hcf, rom_invoke = ...
local computer = computer
local component = component
local unicode = unicode
local addr = computer.getBootAddress()
Journal = {}
Journal.journal = {}
Journal.call_list = {}
function Journal.write(msg)
table.insert(Journal.journal, msg)
for i=1,#Journal.call_list do
Journal.call_list[i](msg)
end
end
function Journal.clear()
Journal.Journal = {}
end
function Journal.attach(func)
table.insert(Journal.call_list, func)
end
local ocelot_card = component.proxy(component.list("ocelot",true)())
Journal.attach(ocelot_card.log)
_G._OSVERSION = "BananaOS 2.21.2025 (BETA)"
-- first things first load up the gpu
local screen = component.list("screen", true)()
local gpu = component.list("gpu", true)()
local w,h
if gpu then
gpu = component.proxy(gpu)
if not gpu.getScreen() then
gpu.bind(screen)
end
w, h = gpu.maxResolution()
gpu.setResolution(w, h)
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.fill(1, 1, w, h, " ")
end
gpu.cursor_y = 5
local function banner(status_)
gpu.setBackground(0xFF0000)
gpu.setForeground(0x000000)
gpu.fill(1,1, w, 3, " ")
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
gpu.fill(2,2, w-2, 1, " ")
if not status_ then
status_ = ""
end
gpu.set(2,2, _OSVERSION .. " " .. status_)
end
local function status(message, m2)
if gpu then
gpu.set(1,gpu.cursor_y, tostring(message))
if gpu.cursor_y >= h then
gpu.copy(1, 2, w, h - 1, 0, -1)
else
gpu.cursor_y = gpu.cursor_y + 1
end
end
banner(m2)
end
gpu.cursor_x = 1
local function scroll(g)
g.copy(1, 2, w, h - 1, 0, -1)
g.fill(1,h,w,h," ")
end
----------------------------------------------
function gpu.getCursor()
return {["x"]=gpu.cursor_x,["y"]=gpu.cursor_y}
end
function gpu.setCursor(x,y)
if x then
gpu.cursor_x = x
end
if y then
gpu.cursor_y = y
end
return gpu.getCursor()
end
function gpu.moveCursor(x,y)
if x then
gpu.cursor_x = gpu.cursor_x + x
end
if y then
gpu.cursor_y = gpu.cursor_y + y
end
return gpu.getCursor()
end
----------------------------------------------
function print(...)
if gpu then
local args = table.pack(...)
for i=1,#args do
args[i] = tostring(args[i])
for j=1, #args[i] do
local letter = args[i]:sub(j,j)
if letter == "\r" then
gpu.cursor_x = 1
elseif letter == "\n" then
gpu.cursor_x = 1
gpu.cursor_y = gpu.cursor_y + 1
else
gpu.set(gpu.cursor_x,gpu.cursor_y, letter)
gpu.cursor_x = gpu.cursor_x + 1
if gpu.cursor_x > w then
gpu.cursor_y = gpu.cursor_y + 1
gpu.cursor_x = 1
end
if gpu.cursor_y > h then
gpu.cursor_y = gpu.cursor_y - 1
scroll(gpu)
end
end
end
end
end
end
status("Initializing packages", "package")
local package = loadfile("/lib/package.lua")(loadfile)
_G.component = nil
_G.computer = nil
_G.unicode = nil
_G.package = package
package.loaded.component = component
package.loaded.computer = computer
package.loaded.unicode = unicode
package.loaded.filesystem = loadfile("/lib/filesystem.lua")(false)
function AlignString(String,Number,append)
if not append then
append = " "
end
String = tostring(String)
if #String > Number then
while #String > Number do
String = String:sub(1, -2)
end
String = String:sub(1, -5) .. "..."
end
if #String < Number then
while #String < Number do
String = String .. append
end
end
return String
end
status("Running boot scripts")
local scripts = {}
for _, file in ipairs(rom_invoke(addr, "list", "/boot/scripts/")) do
local path = "/boot/scripts/" .. file
if not rom_invoke(addr, "isDirectory", path) then
table.insert(scripts, path)
end
end
table.sort(scripts)
for i = 1, #scripts do
status(" -"..scripts[i], string.format("scripts (%s/%s)",i,#scripts))
loadfile(scripts[i])(loadfile, rom_invoke, status, banner)
end
status("Mounting directories", "mounting")
local fs = require("filesystem")
fs.mount(computer.getBootAddress(),"/")
if computer.tmpAddress() then
fs.mount(computer.tmpAddress(), "/tmp/")
end

View File

@ -0,0 +1,3 @@
{
["test"] = "test"
}

0
test/home/.bshrc Normal file
View File

View File

@ -0,0 +1,24 @@
local fs = require("filesystem")
local tests = {
{["expected"]="/", ["value"]="/testFile"},
{["expected"]="/tmp/",["value"]="/tmp/ggg"},
{["expected"]="/tmp/",["value"]="/tmp/this/is/a/long/path"},
{["expected"]="/", ["value"]="/home/tmp/tmp"},
{["expected"]="/tmp/",["value"]="/tmp/"},
{["expected"]=false,["value"]="mnt/"},
}
for i=1, #tests do
local result = fs.findNode(tests[i].value)
if result == false then
print(string.format("Failed! Expected : %s got : %s\r\n",AlignString(tests[i].expected,16),result))
else
result = tostring(result.path)
if result == tests[i].expected then
print(string.format("Success! Expected : %s got : %s\r\n",AlignString(tests[i].expected,16),result))
else
print(string.format("Failed! Expected : %s got : %s\r\n",AlignString(tests[i].expected,16),result))
end
end
end

11
test/home/test.lua Normal file
View File

@ -0,0 +1,11 @@
local fs = require("filesystem")
local a = fs.open("/tmp/test.txt", "w")
fs.write(a,"error(\"awesome!\")")
fs.close(a)
fs.makeDirectory("/tmp/awesome/")
local a = fs.open("/tmp/awesome/abcd", "w")
fs.write(a,"error(\"what!!!\")")
fs.close(a)

35
test/init.lua Normal file
View File

@ -0,0 +1,35 @@
local addr = computer.getBootAddress()
local _component = component -- gets overridden later
local function loadfile(file)
local handle = assert(_component.invoke(addr, "open", file))
local buffer = ""
repeat
local data = _component.invoke(addr, "read", handle, math.maxinteger or math.huge)
buffer = buffer .. (data or "")
until not data
_component.invoke(addr, "close", handle)
return load(buffer, "=" .. file, "bt", _G)
end
local function hcf()
local ts = os.time()
while 1 do
if os.time() - ts >= 0.5 then
coroutine.yield()
end
end
end
local function rom_invoke(a, m, ...)
return _component.invoke(a, m, ...)
end
loadfile("/etc/system/boot.lua")(loadfile, hcf, rom_invoke)
--if loadfile("/sbin/de.lua")() == 0 then -- success
-- computer.shutdown()
--else
loadfile("/sbin/bsh.lua")(loadfile)
--end

44
test/lib/event.lua Normal file
View File

@ -0,0 +1,44 @@
_G.event = {}
local computer = require("computer")
function event.pull(name, timeout)
local rawSignal = {}
local signals_recieved_in_mean_time = {}
local timeouts = 0
if not timeout then
timeout = 99999999999
end
while rawSignal[1] ~= name do
-- pull any signal
rawSignal = table.pack(computer.pullSignal(0.1))
-- if no signal then add to time timeout
if rawSignal[1] == nil then
timeouts = timeouts + 0.1
else
if rawSignal[1] ~= name then
-- not the signal, push to the signals we got in the mean time
table.insert(signals_recieved_in_mean_time,rawSignal)
else
-- got the signal
break
end
end
if timeouts >= timeout then
-- we never got the signal :(
return nil
end
end
-- rethrow all signals... they weren't what we wanted
if #signals_recieved_in_mean_time > 0 then
for i in ipairs(signals_recieved_in_mean_time) do
computer.pushSignal(table.unpack(signals_recieved_in_mean_time[i]))
end
end
return table.unpack(rawSignal)
end
return event

175
test/lib/filesystem.lua Normal file
View File

@ -0,0 +1,175 @@
local debug = ...
local filesystem = {}
local component = require("component")
local computer = require("computer")
local mounts = {}
--false if file, true if dir
local function isFileOrDir(path)
return (string.sub(path, -1) == "/")
end
local function removeFilename(path) -- this sucks
local t = {}
local s = ""
for i in string.gmatch(path, "[^/]+") do
table.insert(t,i)
end
table.remove(t,#t)
if #t == 0 then
return "/"
end
for i=1,#t do
s = s .. t[i] .. "/"
end
if s:sub(1,1) ~= "/" then
s = "/" .. s
end
return s
end
local function log(msg,d)
if d then
if debug then
Journal.write(msg)
end
elseif not d then
Journal.write(msg)
end
end
-- Mount/node handling
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.findNode(path,skipFileDirCheck)
--go through mounts
-- abc - / 1st iteration, does match
-- def - /mnt 2nd iteration, matches better
if not skipFileDirCheck then
if not isFileOrDir(path) then
path = removeFilename(path)
end
end
local candidate = nil
local lastNum = 0
for i=1, #mounts do
local s,e = string.find(path,mounts[i].path)
log(string.format(" [FILESYSTEM.findNode] s:%s e:%s path:%s candidate:%s lastNum:%s - tagainst %s, is id %s",s,e,path,candidate,lastNum,mounts[i].path,mounts[i].disk.address or "n/a"), true)
if e == nil then
e = 0
end
if e > lastNum and s == 1 then
candidate = mounts[i]
lastNum = e
end
end
if lastNum == 0 then
log(" [FILESYSTEM.findNode] failed", true)
return false, "did not find any matching"
else
log(" [FILESYSTEM.findNode] candidate has addr "..candidate.disk.address, true)
return candidate, nil, lastNum
end
end
function filesystem.mount(disk, path)
log(string.format(" [FILESYSTEM] mounting %sas %s", AlignString(disk,7),path),false)
-- check if disk exists
if component.get(disk, "filesystem") then
table.insert(mounts, {
["disk"]=component.proxy(disk),
["path"]=path
})
return mounts[#mounts]
else
log(string.format(" [FILESYSTEM] drive does not exist", false))
return nil, "no filesystem at address"
end
end
-- File operations
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.open(path, mode)
local mount,reason,lastNum = filesystem.findNode(path)
assert(mount,reason)
local id = mount.disk.open(path:sub(lastNum),mode)
assert(id, string.format("id is '%s', not a handle, when opening '%s' (actually '%s') as '%s'",id,path,path:sub(lastNum),mode))
return {["id"]=id,["disk"]=mount}
end
function filesystem.write(handle, data)
handle.disk.disk.write(handle.id,data)
end
function filesystem.read(handle,count)
if count == nil then
count = math.maxinteger or math.huge
end
local buffer = ""
repeat
local data = handle.disk.disk.read(handle.id, count)
buffer = buffer .. (data or "")
until not data
return buffer
end
function filesystem.close(handle)
return handle.disk.disk.close(handle.id)
end
-- Directory operations
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.makeDirectory(path)
local addr,reason,lastNum = filesystem.findNode(path,true)
assert(addr, reason)
return addr.disk.makeDirectory(path:sub(lastNum))
end
-- Misc
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.exists(path)
local addr,reason,lastNum = filesystem.findNode(path)
assert(addr, reason)
if addr.disk.isDirectory(path:sub(lastNum)) or
addr.disk.exists(path:sub(lastNum)) then
return true
end
return false
end
function filesystem.loadfile(path, workspace)
local handle = filesystem.open(path, "r")
local data = filesystem.read(handle)
filesystem.close(handle)
if workspace == nil then
return load(data, "=" .. path, "bt", _G)
else
return load(data, "=" .. path, "bt", workspace)
end
end
function filesystem.getlisting(path) -- handle.disk.files[path]
local mount,reason,lastNum = filesystem.findNode(path)
assert(mount, reason)
return mount.disk.list(path:sub(lastNum))
end
return filesystem

223
test/lib/filesystem.lua.old Normal file
View File

@ -0,0 +1,223 @@
local debug = ...
local filesystem = {}
local component = require("component")
local computer = require("computer")
local mounts = {}
--false if file, true if dir
local function isFileOrDir(path)
return (string.sub(path, -1) == "/")
end
local function removeFilename(path) -- this sucks
local t = {}
local s = ""
for i in string.gmatch(path, "[^/]+") do
table.insert(t,i)
end
table.remove(t,#t)
if #t == 0 then
return "/"
end
for i=1,#t do
s = s .. t[i] .. "/"
end
if s:sub(1,1) ~= "/" then
s = "/" .. s
end
return s
end
local function log(msg,d)
if d then
if debug then
Journal.write(msg)
end
elseif not d then
Journal.write(msg)
end
end
-- Mount/node handling
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.findNode(path)
--go through mounts
-- abc - / 1st iteration, does match
-- def - /mnt 2nd iteration, matches better
if not isFileOrDir(path) then
path = removeFilename(path)
end
local candidate = nil
local lastNum = 0
for i=1, #mounts do
local s,e = string.find(path,mounts[i].path)
log(string.format(" [FILESYSTEM.findNode] s:%s e:%s path:%s candidate:%s lastNum:%s - tagainst %s, is id %s",s,e,path,candidate,lastNum,mounts[i].path,mounts[i].disk.address or "n/a"), true)
if e == nil then
e = 0
end
if e > lastNum and s == 1 then
candidate = mounts[i]
lastNum = e
end
end
if lastNum == 0 then
log(" [FILESYSTEM.findNode] failed", true)
return false, "did not find any matching"
else
log(" [FILESYSTEM.findNode] candidate has addr "..candidate.disk.address, true)
return candidate
end
end
function filesystem.mount(disk, path)
log(string.format(" [FILESYSTEM] mounting %sas %s", AlignString(disk,7),path),false)
if disk == nil then
table.insert(mounts, {
["disk"]={["address"]="n/a"},
["path"]=path,
["isVirtual"]=true,
["files"]={}, -- {[path] = data}
["handles"]={}
})
log(" [FILESYSTEM] drive is virtual")
return mounts
end
-- check if disk exists
if component.get(disk, "filesystem") then
table.insert(mounts, {
["disk"]=component.proxy(disk),
["path"]=path,
["isVirtual"]=false
})
return mounts[#mounts]
else
log(string.format(" [FILESYSTEM] drive does not exist", false))
return nil, "no filesystem at address"
end
end
-- File operations
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.open(path, mode)
local mount, reason = filesystem.findNode(path)
assert(mount,reason)
if mount.isVirtual then
table.insert(mount.handles,{
["path"] = path,
["mode"] = mode,
["ptr"] = 1
})
return {["id"]=#mount.handles,["disk"]=mount}
else --untested
local id = mount.disk.open(path,mode)
assert(id, string.format("id is '%s', not a handle, when opening '%s' as '%s'",id,path,mode))
return {["id"]=id,["disk"]=mount}
end
end
function filesystem.write(handle, data)
if handle.disk.isVirtual then
local mode = handle.disk.handles[handle.id].mode
local path = handle.disk.handles[handle.id].path
if mode == "a" or mode == "ab" then
error("not implemented")
elseif mode == "w" or mode == "wb" then
handle.disk.files[path] = data
return
else
error(string.format("mode '%s' not understood",mode))
end
else
handle.disk.disk.write(handle.id,data)
end
end
function filesystem.read(handle,count)
if count == nil then
count = math.maxinteger or math.huge
end
if handle.disk.isVirtual then
local d = handle.disk
local a = d.files[d.handles[handle.id].path]
:sub(d.handles[handle.id].ptr,d.handles[handle.id].ptr+count-1)
d.handles[handle.id].ptr = d.handles[handle.id].ptr +count
return a
else --untested
local buffer = ""
repeat
local data = handle.disk.disk.read(handle.id, count)
buffer = buffer .. (data or "")
until not data
return buffer
end
end
function filesystem.close(handle)
if handle.disk.isVirtual then
handle.disk.handles[handle.id] = nil
return
else --untested
return handle.disk.disk.close(handle.id)
end
end
-- Misc
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.exists(path) -- weird, doesnt w
local addr = filesystem.findNode(path)
if addr == nil then
return false
end
if addr.disk.isDirectory(path) or
addr.disk.exists(path) then
return true
end
return false
end
function filesystem.loadfile(path, workspace)
local handle = filesystem.open(path, "r")
local data = filesystem.read(handle)
filesystem.close(handle)
if workspace == nil then
return load(data, "=" .. path, "bt", _G)
else
return load(data, "=" .. path, "bt", workspace)
end
end
function filesystem.getlisting(path) -- handle.disk.files[path]
local mount, reason = filesystem.findNode(path)
assert(mount, reason)
if mount.isVirtual then
local a = {}
print(#mount.files)
for b=1, #mount.files do
error(b)
table.insert(a, mount.files[b]:gmatch("[^/]+"))
end
print(a[1])
else
return mount.disk.list(path)
end
end
return filesystem

40
test/lib/package.lua Normal file
View File

@ -0,0 +1,40 @@
local loadfile = ...
local package = {}
local loaded = {
["_G"] = _G,
["bit32"] = bit32,
["coroutine"] = coroutine,
["math"] = math,
["os"] = os,
["package"] = package,
["string"] = string,
["table"] = table,
}
local pkg_path = "/lib/?.lua"
package.loaded = loaded
function package.search(file,path)
for path in path:gmatch("[^;]+") do
local possible = path:gsub("%?", file)
local s, _ = pcall(loadfile, possible)
if s then
return possible
end
end
return false
end
function require(module)
if package.loaded[module] then
return package.loaded[module]
else
local path = package.search(module,pkg_path)
assert(path, "module not found")
local mod = loadfile(path)()
package.loaded[module] = mod
return mod
end
end
return package

204
test/sbin/bsh.lua Normal file
View File

@ -0,0 +1,204 @@
local bsh = {}
local component = require("component")
local computer = require("computer")
local event = require("event")
local fs = require("filesystem")
local package = require("package")
_G.ExecPath = "/sbin/?.lua;/bin/?.lua"
if fs.exists("/etc/motd") then
local motd_h = fs.open("/etc/motd", "r")
print(fs.read(motd_h))
fs.close(motd_h)
end
print("\n")
-- BUG: when in /bin directory, running something tries to run /binhello.lua
-- FEAT: autofill slashes, and .lua
-- FEAT: handle ..
bsh.running = true
local cwd = "/home/"
local function keyin(timeout)
while true do
local _,_,ascii,code,_ = event.pull("key_down",timeout)
return ascii,code
end
end
function bsh.split(str)
local words = {}
for word in str:gmatch("%S+") do
table.insert(words, word)
end
return words
end
function bsh.is_in_arr(arr,elem)
for i in ipairs(arr) do
if tostring(arr[i]) == tostring(elem) then
return true
end
end
return false
end
function bsh.command(buffer)
if #buffer == 0 then
return
end
local command = bsh.split(buffer)
if command[1] == "ls" then
local cwdls
if command[2] == nil then
cwdls = fs.getlisting(cwd)
else
cwdls = fs.getlisting(command[2])
end
if cwdls ~= nil then
for i = 1, #cwdls do
print(cwdls[i] .. " ")
end
else
print("(Nothing here!)")
end
print("\r\n")
elseif command[1] == "cd" then
if command[2] == nil then
error("no argument")
else
cwd = command[2]
end
elseif command[1] == "clear" then
local w,h=component.gpu.getResolution()
component.gpu.fill(1,1,w,h," ")
component.gpu.setCursor(2,1)
elseif command[1] == "exit" then
bsh.running = false
else -- execute file, this sucks tho
local location = command[1]
local s,_ = pcall(fs.loadfile,location)
-- is in cwd?
if not s then
if bsh.is_in_arr(fs.getlisting(cwd),command[1]) then
location = cwd .. command[1]
else
-- no, check path
local a = package.search(command[1],ExecPath)
if a ~= false then
location = a
else
error("command not found")
end
end
end
local a = fs.loadfile(location)
a(command)
end
end
local function prompt()
print(cwd .." #> ")
end
print("bsh v3\n")
local buffer = ""
local gpu = component.gpu
prompt()
local cursor = ""
local cursorOnOff = 1
local history = {}
local history_index = 1
while bsh.running do
local nextkeycode, code = keyin()
local charAtCurLocation = " "
local cur = gpu.getCursor()
--print(nextkeycode,"=",code," ")
if nextkeycode == nil and code == nil then
-- timeout reached, invert cursor
cursorOnOff = cursorOnOff * -1
if cursorOnOff == 1 then
charAtCurLocation = gpu.get(cur.x,cur.y)
gpu.set(cur.x,cur.y,cursor)
else
gpu.set(cur.x,cur.y,charAtCurLocation)
end
end
if nextkeycode == 0 or nextkeycode == nil then
local preBuffer=buffer
if code == 42 then -- shift
-- ignore
elseif code == 200 then -- up
if history[history_index] then
buffer = history[history_index]
history_index = history_index - 1
gpu.setCursor(1)
prompt()
for i=1,#preBuffer do print(" ") end
gpu.setCursor(1)
prompt()
print(buffer)
end
elseif code == 208 then -- down
if history[history_index+1] then
history_index = history_index + 2
buffer = history[history_index]
gpu.setCursor(1)
prompt()
for i=1,#preBuffer do print(" ") end
gpu.setCursor(1)
prompt()
print(buffer)
end
end
else
gpu.set(cur.x,cur.y,charAtCurLocation)
local nextkey = string.char(nextkeycode)
if nextkeycode == 13 then --enter
table.insert(history, buffer)
history_index = #history
if cursorOnOff ~= 1 then
gpu.set(cur.x,cur.y,charAtCurLocation)
end
print("\n")
local success, reason = xpcall(bsh.command, function(a)
return {a, debug.traceback()}
end, buffer)
if not success then
if reason then
print(reason[1].."\n\n")
component.gpu.setForeground(0xff3333)
print(reason[2])
component.gpu.setForeground(0xffffff)
end
end
buffer = ""
nextkeycode = nil
print("\n")
prompt()
elseif nextkeycode == 8 then --backsp
if #buffer ~= 0 then
buffer = buffer:sub(1, -2)
gpu.moveCursor(-1)
print(" ")
gpu.moveCursor(-1)
end
else
buffer = buffer .. nextkey
print(nextkey)
end
end
end

133
test/sbin/de.lua Normal file
View File

@ -0,0 +1,133 @@
local component = require("component")
local computer = require("computer")
local fs = require("filesystem")
local event = require("event")
-- get GPU
local gpu = component.proxy(component.list("gpu", true)())
if gpu == nil then
return -1
end
local resolution = {}
resolution.w, resolution.h = gpu.maxResolution()
local bg_color = 0xa2cffe
local touch_listeners = {} -- {x start,y start,x end,y end,function to call, with args}
local windows = {} -- {WINDOW_NAME,X,Y,WIDTH,HEIGHT}
-- local
gpu.setResolution(resolution.w, resolution.h)
local function add_touch_listener(xs,ys,xe,ye,call,args)
table.insert(touch_listeners, {xs,ys,xe,ye,call,args})
return #touch_listeners
end
local function draw_nav()
gpu.setBackground(0xffffff)
gpu.setForeground(0xffffff)
gpu.fill(1, 1, resolution.w, 1, " ")
gpu.setForeground(0x000000)
gpu.setBackground(0xffffff)
gpu.set(2,1, "@")
local totalmem = computer.totalMemory()
local freemem = computer.freeMemory()
gpu.set(6,1, tostring(totalmem-freemem) .. " b / " .. tostring(totalmem) .. " b")
gpu.setBackground(bg_color)
end
local function draw_bg()
gpu.setBackground(bg_color)
gpu.fill(1, 2, resolution.w, resolution.h, " ")
end
local function draw_windows()
for i = 1, #windows do
gpu.setBackground(0x000000)
gpu.setForeground(0xffffff)
gpu.fill(
windows[i][2],
windows[i][3]-1,
windows[i][2]+windows[i][4],
windows[i][3]-1,
" "
)
gpu.set(windows[i][2], windows[i][3]-1, "X | " .. windows[i][1])
gpu.setBackground(0xaaaaaa)
gpu.fill(
windows[i][2],
windows[i][3],
windows[i][2]+windows[i][4],
windows[i][3]+windows[i][5],
" "
)
end
end
local function keyin()
return event.pull("key_down")
end
local function open_exec_menu(args)
gpu.setBackground(0xdadada)
gpu.fill(1,3,resolution.w, 1, " ")
gpu.setBackground(bg_color)
local grab = true
local buffer = ""
local curr_loc_x = 1
while grab do
local _,_,next_key = keyin()
if next_key == 13 then
local result = table.pack(pcall(fs.dofile, buffer))
if not result[1] then
print(result[2] .. "\n")
end
buffer = ""
curr_loc_x = 1
grab = false
elseif next_key == 8 then
if #buffer ~= 0 then
buffer = buffer:sub(1, -2)
gpu.set(curr_loc_x-1, 2, " ")
curr_loc_x = curr_loc_x - 1
end
else
buffer = buffer .. string.char(next_key)
gpu.set(curr_loc_x, 2, string.char(next_key))
curr_loc_x = curr_loc_x + 1
end
end
gpu.setBackground(bg_color)
gpu.fill(1,2,resolution.w, 3, " ")
end
draw_bg()
draw_nav()
add_touch_listener(2, 1, 2, 1, open_exec_menu, {})
while true do
local event,uuid,x,y = computer.pullSignal(0.3)
if event == "touch" then
for i = 1, #touch_listeners do
if touch_listeners[i][1] <= x and x <= touch_listeners[i][3] then
if touch_listeners[i][2] <= y and y <= touch_listeners[i][4] then
touch_listeners[i][5](touch_listeners[i][6])
end
end
end
end
draw_nav()
draw_windows()
end

4
test/sbin/free.lua Normal file
View File

@ -0,0 +1,4 @@
local computer = require("computer")
local free = computer.freeMemory()
local total = computer.totalMemory()
print(string.format("Total%12d\nUsed%13d\nFree%13d\n", total, total - free, free))

15
test/sbin/lspci.lua Normal file
View File

@ -0,0 +1,15 @@
local computer = require("computer")
local function getModel(desc)
local name
for _, dev in pairs(computer.getDeviceInfo()) do
if dev.description == desc then
name = dev.product
break
end
end
return name
end
print(getModel("APU"))