Initial commit
This commit is contained in:
commit
e9e68d9f28
175 changed files with 10337 additions and 0 deletions
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# **FREAX**
|
||||
**FREAX** is a operating system written in Lua and can only be ran in ComputerCraft, a Minecraft modification. It is designed to be as Linux-y as possible.
|
||||
|
||||
# **Install**
|
||||
Just clone the repository and move everything into your computer's data folder. A advanced installation documentation will be added soon.
|
26
bin/alias
Normal file
26
bin/alias
Normal file
|
@ -0,0 +1,26 @@
|
|||
local tArgs = { ... }
|
||||
if #tArgs > 2 then
|
||||
local programName = "alias"
|
||||
print("Usage: " .. programName .. " <alias> <program>")
|
||||
return
|
||||
end
|
||||
|
||||
local sAlias = tArgs[1]
|
||||
local sProgram = tArgs[2]
|
||||
|
||||
if sAlias and sProgram then
|
||||
-- Set alias
|
||||
shell.setAlias(sAlias, sProgram)
|
||||
elseif sAlias then
|
||||
-- Clear alias
|
||||
shell.clearAlias(sAlias)
|
||||
else
|
||||
-- List aliases
|
||||
local tAliases = shell.aliases()
|
||||
local tList = {}
|
||||
for sAlias, sCommand in pairs(tAliases) do
|
||||
table.insert(tList, sAlias .. ":" .. sCommand)
|
||||
end
|
||||
table.sort(tList)
|
||||
textutils.pagedTabulate(tList)
|
||||
end
|
14
bin/apis
Normal file
14
bin/apis
Normal file
|
@ -0,0 +1,14 @@
|
|||
local tApis = {}
|
||||
for k, v in pairs(_G) do
|
||||
if type(k) == "string" and type(v) == "table" and k ~= "_G" then
|
||||
table.insert(tApis, k)
|
||||
end
|
||||
end
|
||||
table.insert(tApis, "shell")
|
||||
table.insert(tApis, "package")
|
||||
if multishell then
|
||||
table.insert(tApis, "multishell")
|
||||
end
|
||||
table.sort(tApis)
|
||||
|
||||
textutils.pagedTabulate(tApis)
|
131
bin/archiver
Normal file
131
bin/archiver
Normal file
|
@ -0,0 +1,131 @@
|
|||
print("Debian CC Archiver v0.1 by 1Ridav")
|
||||
tArgs = {...}
|
||||
local function getPath(input)
|
||||
if string.sub(input, 1, 1)=="/" then path=input else
|
||||
path=("/" .. shell.dir() .. "/" .. input) end
|
||||
return path
|
||||
end
|
||||
if tArgs[2] then
|
||||
tArgs[2]=getPath(tArgs[2])
|
||||
end
|
||||
|
||||
local FFormat = ".arch"
|
||||
local nFile, nDir, size = 0, 0
|
||||
|
||||
if #tArgs < 3 then
|
||||
print("Usage:"
|
||||
.."\narchiver zip <DIR> <ZIPname> [DIRtoSkip] [DIRtoSkip]"
|
||||
.."\narchiver unzip <ZIPname> <DIR>")
|
||||
end
|
||||
|
||||
local function fopen(path, mode)
|
||||
local f = fs.open(path, mode)
|
||||
if not f then
|
||||
print("ERROR: Could not open "..path.." with mode \""..mode.."\"")
|
||||
exit()
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
local function skip(df)
|
||||
for i = 3, #tArgs do
|
||||
if tArgs[i] == fs.getName(df) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
for i = 4, #tArgs do
|
||||
if tArgs[i] == fs.getName(df) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function zip(file)
|
||||
print("zipping: ".. file)
|
||||
local f = fopen(file, "r")
|
||||
local z = textutils.serialize(f.readAll())
|
||||
f.close()
|
||||
return z
|
||||
end
|
||||
|
||||
local function ZIP(path)
|
||||
local list = fs.list(path)
|
||||
local array = {}
|
||||
local t, name, d = 0, "", 0
|
||||
|
||||
for i = 2, #list * 2, 2 do
|
||||
t = i/2
|
||||
local tpath = path.."/"..list[t]
|
||||
if fs.isDir(tpath) then
|
||||
if not skip(tpath) then
|
||||
name = "D:"..list[t]
|
||||
array[i] = ZIP(tpath)
|
||||
nDir = nDir + 1
|
||||
end
|
||||
else
|
||||
name = "F:"..list[t]
|
||||
array[i] = zip(tpath)
|
||||
nFile = nFile + 1
|
||||
end
|
||||
array[i - 1] = name
|
||||
end
|
||||
|
||||
return textutils.serialize(array)
|
||||
end
|
||||
|
||||
local function unzip(text, path)
|
||||
print("unzipping: "..path)
|
||||
local f = fopen(path, "w")
|
||||
f.write(textutils.unserialize(text))
|
||||
f.close()
|
||||
end
|
||||
|
||||
local function UNZIP(text, path)
|
||||
local array = textutils.unserialize(text)
|
||||
local unz, dp
|
||||
local d = 0
|
||||
for i = 2, #array, 2 do
|
||||
if string.sub(array[i-1], 1, 1) == "D" then
|
||||
dp = string.sub(array[i-1], 3, #array[i-1])
|
||||
fs.makeDir(path.."/"..dp)
|
||||
UNZIP(array[i], path.."/"..dp)
|
||||
nDir = nDir + 1
|
||||
elseif string.sub(array[i-1], 1, 1) == "F" then
|
||||
local p = string.sub(array[i-1], 3, #array[i-1])
|
||||
unzip(array[i], path.."/"..p)
|
||||
nFile = nFile + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function result()
|
||||
print("\nDone"
|
||||
,"\n size: "
|
||||
,size, " B "
|
||||
,math.floor(size/1024), " KB"
|
||||
,"\n Files: ", nFile
|
||||
,"\n Folders: ", nDir
|
||||
)
|
||||
end
|
||||
|
||||
if tArgs[1] == "zip" then
|
||||
if fs.exists(tArgs[2]) and fs.isDir(tArgs[2]) then
|
||||
local zipped = ZIP(shell.resolve(tArgs[2]))
|
||||
local f = fs.open(tArgs[3]..FFormat, "w")
|
||||
f.write(zipped)
|
||||
f.close()
|
||||
zipped = nil
|
||||
size = fs.getSize(tArgs[3]..FFormat)
|
||||
result()
|
||||
end
|
||||
|
||||
elseif tArgs[1] == "unzip" then
|
||||
local f = fopen(tArgs[2], "r")
|
||||
if not fs.exists(tArgs[3]) then
|
||||
fs.makeDir(tArgs[3])
|
||||
end
|
||||
UNZIP(f.readAll(), tArgs[3])
|
||||
size = fs.getSize(tArgs[2])
|
||||
result()
|
||||
end
|
16
bin/attach
Normal file
16
bin/attach
Normal file
|
@ -0,0 +1,16 @@
|
|||
if periphemu == nil then error("Attaching peripherals is not supported in vanilla mode.") end
|
||||
local args = { ... }
|
||||
if args[1] == "list" then
|
||||
print("Available peripheral types:")
|
||||
for _,p in ipairs(periphemu.names()) do print(p) end
|
||||
elseif type(args[1]) ~= "string" or type(args[2]) ~= "string" then
|
||||
print("Usage: attach <side> <type> [options...]\n attach list")
|
||||
else
|
||||
if peripheral.isPresent(args[1]) and peripheral.getType(args[1]) == args[2] then
|
||||
print("Peripheral already attached")
|
||||
return
|
||||
end
|
||||
if tonumber(args[3]) ~= nil then args[3] = tonumber(args[3]) end
|
||||
local ok, err = periphemu.create(args[1], args[2], args[3])
|
||||
if not ok then printError("Could not attach peripheral" .. (err and ": " .. err or "")) end
|
||||
end
|
18
bin/cat
Normal file
18
bin/cat
Normal file
|
@ -0,0 +1,18 @@
|
|||
local tArgs = {...}
|
||||
|
||||
if #tArgs >= 1 then
|
||||
path = shell.resolve(tArgs[1])
|
||||
if fs.isReadOnly(path) and not security.getSU() then
|
||||
-- prevent users from seeing unauthorized code
|
||||
-- they should only be able to see their own files and ones in /var/log
|
||||
exception.throw("SecurityException", path)
|
||||
return
|
||||
end
|
||||
if not fs.exists(path) or fs.isDir(path) then
|
||||
kerneldraw.printAppInfo("cat", "File or directory not found")
|
||||
else
|
||||
textutils.pagedPrint(kernel.printFile(path))
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("cat", "No file specified")
|
||||
end
|
14
bin/cd
Normal file
14
bin/cd
Normal file
|
@ -0,0 +1,14 @@
|
|||
local tArgs = { ... }
|
||||
if #tArgs < 1 then
|
||||
local programName = arg[0] or fs.getName(shell.getRunningProgram())
|
||||
print("Usage: " .. programName .. " <path>")
|
||||
return
|
||||
end
|
||||
|
||||
local sNewDir = shell.resolve(tArgs[1])
|
||||
if fs.isDir(sNewDir) then
|
||||
shell.setDir(sNewDir)
|
||||
else
|
||||
print("Not a directory")
|
||||
return
|
||||
end
|
44
bin/clear
Normal file
44
bin/clear
Normal file
|
@ -0,0 +1,44 @@
|
|||
local tArgs = { ... }
|
||||
|
||||
local function printUsage()
|
||||
local programName = "clear"
|
||||
print("Usages:")
|
||||
print(programName)
|
||||
print(programName .. " screen")
|
||||
print(programName .. " palette")
|
||||
print(programName .. " all")
|
||||
end
|
||||
|
||||
local function clear()
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
end
|
||||
|
||||
local function clearPixels()
|
||||
if term.getGraphicsMode then
|
||||
term.setGraphicsMode(1)
|
||||
term.clear()
|
||||
term.setGraphicsMode(0)
|
||||
end
|
||||
end
|
||||
|
||||
local function resetPalette()
|
||||
for i = 0, 15 do
|
||||
term.setPaletteColour(2^i, term.nativePaletteColour(2^i))
|
||||
end
|
||||
end
|
||||
|
||||
local sCommand = tArgs[1] or "screen"
|
||||
if sCommand == "screen" then
|
||||
clear()
|
||||
elseif sCommand == "palette" then
|
||||
resetPalette()
|
||||
elseif sCommand == "graphics" then
|
||||
clearPixels()
|
||||
elseif sCommand == "all" then
|
||||
clear()
|
||||
clearPixels()
|
||||
resetPalette()
|
||||
else
|
||||
printUsage()
|
||||
end
|
23
bin/convert
Normal file
23
bin/convert
Normal file
|
@ -0,0 +1,23 @@
|
|||
local args = {...}
|
||||
|
||||
local function checksys(txt)
|
||||
if txt == "kernel" or txt == "gui" or txt == "app" or txt == "log" or txt == "config" or txt == "manual" or txt == "search" or txt == "tpm" or txt == "exception" or string.find(txt, "boot/") or string.find(txt, "system/") or string.find(txt, ".freax/startup") then
|
||||
kerneldraw.printAppWarning("kernel", "attempt to perform restricted operations")
|
||||
--return true
|
||||
end
|
||||
end
|
||||
|
||||
if #args < 1 or not fs.exists(shell.resolveProgram(args[1])) or fs.isDir(shell.resolve(args[1])) then
|
||||
kerneldraw.printAppInfo("config", "No file specified")
|
||||
return
|
||||
end
|
||||
|
||||
if not checksys(shell.resolveProgram(args[1])) then
|
||||
if os.loadAPI(shell.resolveProgram(args[1])) then
|
||||
config.save(_G[args[1]], textutils.serialize(args[1]))
|
||||
os.unloadAPI(args[1])
|
||||
kerneldraw.printAppSuccess("config", "Done")
|
||||
end
|
||||
else
|
||||
exception.throw("RestrictedOpsException")
|
||||
end
|
32
bin/cp
Normal file
32
bin/cp
Normal file
|
@ -0,0 +1,32 @@
|
|||
local tArgs = { ... }
|
||||
if #tArgs < 2 then
|
||||
local programName = "cp"
|
||||
print("Usage: " .. programName .. " <source> <destination>")
|
||||
return
|
||||
end
|
||||
|
||||
local sSource = shell.resolve(tArgs[1])
|
||||
local sDest = shell.resolve(tArgs[2])
|
||||
local tFiles = fs.find(sSource)
|
||||
if #tFiles > 0 then
|
||||
for _, sFile in ipairs(tFiles) do
|
||||
if fs.isDir(sDest) then
|
||||
fs.copy(sFile, fs.combine(sDest, fs.getName(sFile)))
|
||||
elseif #tFiles == 1 then
|
||||
if fs.exists(sDest) then
|
||||
printError("Destination exists")
|
||||
elseif fs.isReadOnly(sDest) then
|
||||
printError("Destination is read-only")
|
||||
elseif fs.getFreeSpace(sDest) < fs.getSize(sFile) then
|
||||
printError("Not enough space")
|
||||
else
|
||||
fs.copy(sFile, sDest)
|
||||
end
|
||||
else
|
||||
printError("Cannot overwrite file multiple times")
|
||||
return
|
||||
end
|
||||
end
|
||||
else
|
||||
printError("No matching files")
|
||||
end
|
1
bin/credits
Normal file
1
bin/credits
Normal file
|
@ -0,0 +1 @@
|
|||
shell.run("/bin/man credits")
|
2
bin/detach
Normal file
2
bin/detach
Normal file
|
@ -0,0 +1,2 @@
|
|||
if periphemu == nil then error("Attaching peripherals is not supported in vanilla mode.") end
|
||||
if type(({...})[1]) ~= "string" then print("Usage: detach <side>") else if not periphemu.remove(({...})[1]) then printError("Could not detach peripheral") end end
|
12
bin/df
Normal file
12
bin/df
Normal file
|
@ -0,0 +1,12 @@
|
|||
local tArgs = {...}
|
||||
local sz = fs.getSize(shell.dir())
|
||||
local fspc = fs.getFreeSpace(shell.dir())
|
||||
|
||||
kerneldraw.printAppInfo("type", fs.getDrive(shell.dir()))
|
||||
if search.findValue(tArgs, "-sB") then
|
||||
kerneldraw.printAppInfo("size", tostring(sz).." B")
|
||||
kerneldraw.printAppInfo("free space", tostring(fspc).." B")
|
||||
elseif search.findValue(tArgs, "-sKB") then
|
||||
kerneldraw.printAppInfo("size", tostring(sz/1024).." KB")
|
||||
kerneldraw.printAppInfo("free space", tostring(fspc/1024).." KB")
|
||||
end
|
21
bin/drive
Normal file
21
bin/drive
Normal file
|
@ -0,0 +1,21 @@
|
|||
local tArgs = { ... }
|
||||
|
||||
-- Get where a directory is mounted
|
||||
local sPath = shell.dir()
|
||||
if tArgs[1] ~= nil then
|
||||
sPath = shell.resolve(tArgs[1])
|
||||
end
|
||||
|
||||
if fs.exists(sPath) then
|
||||
write(fs.getDrive(sPath) .. " (")
|
||||
local nSpace = fs.getFreeSpace(sPath)
|
||||
if nSpace >= 1000 * 1000 then
|
||||
print(math.floor(nSpace / (100 * 1000)) / 10 .. "MB remaining)")
|
||||
elseif nSpace >= 1000 then
|
||||
print(math.floor(nSpace / 100) / 10 .. "KB remaining)")
|
||||
else
|
||||
print(nSpace .. "B remaining)")
|
||||
end
|
||||
else
|
||||
print("No such path")
|
||||
end
|
18
bin/eject
Normal file
18
bin/eject
Normal file
|
@ -0,0 +1,18 @@
|
|||
-- Get arguments
|
||||
local tArgs = { ... }
|
||||
if #tArgs == 0 then
|
||||
local programName = "eject"
|
||||
print("Usage: " .. programName .. " <drive>")
|
||||
return
|
||||
end
|
||||
|
||||
local sDrive = tArgs[1]
|
||||
|
||||
-- Check the disk exists
|
||||
local bPresent = disk.isPresent(sDrive)
|
||||
if not bPresent then
|
||||
print("Nothing in " .. sDrive .. " drive")
|
||||
return
|
||||
end
|
||||
|
||||
disk.eject(sDrive)
|
40
bin/env
Normal file
40
bin/env
Normal file
|
@ -0,0 +1,40 @@
|
|||
if shell.environment == nil then error("Requires the cash shell.") end
|
||||
local args = {...}
|
||||
|
||||
local env = setmetatable({}, {__index = _ENV})
|
||||
local path = shell.path()
|
||||
local unset = {}
|
||||
local cmd = {}
|
||||
local cmdargs = false
|
||||
local nextarg
|
||||
|
||||
for k,v in ipairs(args) do
|
||||
if nextarg then
|
||||
if nextarg == 1 then path = v
|
||||
elseif nextarg == 2 then table.insert(unset, v) end
|
||||
nextarg = nil
|
||||
elseif cmdargs then
|
||||
table.insert(cmd, v)
|
||||
else
|
||||
if v == "-i" then setmetatable(env, {__index = _G})
|
||||
elseif v == "-P" then nextarg = 1
|
||||
elseif v == "-u" then nextarg = 2
|
||||
elseif string.find(v, "=") then env[string.sub(v, 1, string.find(v, "=") - 1)] = string.sub(v, string.find(v, "=") + 1)
|
||||
else table.insert(cmd, v); cmdargs = true end
|
||||
end
|
||||
end
|
||||
|
||||
if #unset > 0 then
|
||||
local oldidx = getmetatable(env).__index
|
||||
local u = {}
|
||||
for k,v in ipairs(unset) do u[v] = true end
|
||||
setmetatable(env, {__index = function(self, name) if u[name] then return nil else return oldidx[name] end end})
|
||||
end
|
||||
|
||||
local oldPath = shell.path()
|
||||
local oldEnv = shell.environment()
|
||||
shell.setPath(path)
|
||||
shell.setEnvironment(env)
|
||||
shell.run(table.unpack(cmd))
|
||||
shell.setPath(oldPath)
|
||||
shell.setEnvironment(oldEnv)
|
5
bin/exit
Normal file
5
bin/exit
Normal file
|
@ -0,0 +1,5 @@
|
|||
if security.getSU() then
|
||||
shell.exit()
|
||||
else
|
||||
kernel.reboot(true)
|
||||
end
|
1
bin/firststeps
Normal file
1
bin/firststeps
Normal file
|
@ -0,0 +1 @@
|
|||
shell.run("/bin/man firststeps")
|
994
bin/gclone
Normal file
994
bin/gclone
Normal file
|
@ -0,0 +1,994 @@
|
|||
local replaceLine = true -- Setting to false may result in corrupted output
|
||||
local preload = type(package) == "table" and type(package.preload) == "table" and package.preload or {}
|
||||
|
||||
local require = require
|
||||
if type(require) ~= "function" then
|
||||
local loading = {}
|
||||
local loaded = {}
|
||||
require = function(name)
|
||||
local result = loaded[name]
|
||||
|
||||
if result ~= nil then
|
||||
if result == loading then
|
||||
error("loop or previous error loading module '" .. name .. "'", 2)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
loaded[name] = loading
|
||||
local contents = preload[name]
|
||||
if contents then
|
||||
result = contents(name)
|
||||
else
|
||||
error("cannot load '" .. name .. "'", 2)
|
||||
end
|
||||
|
||||
if result == nil then result = true end
|
||||
loaded[name] = result
|
||||
return result
|
||||
end
|
||||
end
|
||||
preload["objects"] = function(...)
|
||||
local inflate_zlib = require "deflate".inflate_zlib
|
||||
local sha = require "metis.crypto.sha1"
|
||||
|
||||
local band, bor, lshift, rshift = bit32.band, bit32.bor, bit32.lshift, bit32.rshift
|
||||
local byte, format, sub = string.byte, string.format, string.sub
|
||||
|
||||
local types = { [0] = "none", "commit", "tree", "blob", "tag", nil, "ofs_delta", "ref_delta", "any", "max" }
|
||||
|
||||
--- Get the type of a specific object
|
||||
-- @tparam Object x The object to get the type of
|
||||
-- @treturn string The object's type.
|
||||
local function get_type(x) return types[x.ty] or "?" end
|
||||
|
||||
local event = ("luagit-%08x"):format(math.random(0, 2^24))
|
||||
local function check_in()
|
||||
os.queueEvent(event)
|
||||
os.pullEvent(event)
|
||||
end
|
||||
|
||||
local sha_format = ("%02x"):rep(20)
|
||||
|
||||
local function reader(str)
|
||||
local expected_checksum = format(sha_format, byte(str, -20, -1))
|
||||
local actual_checksum = sha(str:sub(1, -21));
|
||||
if expected_checksum ~= actual_checksum then
|
||||
error(("checksum mismatch: expected %s, got %s"):format(expected_checksum, actual_checksum))
|
||||
end
|
||||
|
||||
str = str:sub(1, -20)
|
||||
|
||||
local pos = 1
|
||||
|
||||
local function consume_read(len)
|
||||
if len <= 0 then error("len < 0", 2) end
|
||||
if pos > #str then error("end of stream") end
|
||||
|
||||
local cur_pos = pos
|
||||
pos = pos + len
|
||||
local res = sub(str, cur_pos, pos - 1)
|
||||
if #res ~= len then error("expected " .. len .. " bytes, got" .. #res) end
|
||||
return res
|
||||
end
|
||||
|
||||
local function read8()
|
||||
if pos > #str then error("end of stream") end
|
||||
local cur_pos = pos
|
||||
pos = pos + 1
|
||||
return byte(str, cur_pos)
|
||||
end
|
||||
|
||||
return {
|
||||
offset = function() return pos - 1 end,
|
||||
read8 = read8,
|
||||
read16 = function() return (read8() * (2^8)) + read8() end,
|
||||
read32 = function() return (read8() * (2^24)) + (read8() * (2^16)) + (read8() * (2^8)) + read8() end,
|
||||
read = consume_read,
|
||||
|
||||
close = function()
|
||||
if pos ~= #str then error(("%d of %d bytes remaining"):format(#str - pos + 1, #str)) end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
--- Consume a string from the given input buffer
|
||||
--
|
||||
-- @tparam Reader handle The handle to read from
|
||||
-- @tparam number size The number of decompressed bytes to read
|
||||
-- @treturn string The decompressed data
|
||||
local function get_data(handle, size)
|
||||
local tbl, n = {}, 1
|
||||
|
||||
inflate_zlib {
|
||||
input = handle.read8,
|
||||
output = function(x) tbl[n], n = string.char(x), n + 1 end
|
||||
}
|
||||
|
||||
local res = table.concat(tbl)
|
||||
if #res ~= size then error(("expected %d decompressed bytes, got %d"):format(size, #res)) end
|
||||
return res
|
||||
end
|
||||
|
||||
--- Decode a binary delta file, applying it to the original
|
||||
--
|
||||
-- The format is described in more detail in [the Git documentation][git_pack]
|
||||
--
|
||||
-- [git_pack]: https://git-scm.com/docs/pack-format#_deltified_representation
|
||||
--
|
||||
-- @tparam string original The original string
|
||||
-- @tparam string delta The binary delta
|
||||
-- @treturn string The patched string
|
||||
local function apply_delta(original, delta)
|
||||
local delta_offset = 1
|
||||
local function read_size()
|
||||
local c = byte(delta, delta_offset)
|
||||
delta_offset = delta_offset + 1
|
||||
|
||||
local size = band(c, 0x7f)
|
||||
local shift = 7
|
||||
while band(c, 0x80) ~= 0 do
|
||||
c, delta_offset = byte(delta, delta_offset), delta_offset + 1
|
||||
size, shift = size + lshift(band(c, 0x7f), shift), shift + 7
|
||||
end
|
||||
|
||||
return size
|
||||
end
|
||||
|
||||
local original_length = read_size()
|
||||
local patched_length = read_size()
|
||||
if original_length ~= #original then
|
||||
error(("expected original of size %d, got size %d"):format(original_length, #original))
|
||||
end
|
||||
|
||||
local parts, n = {}, 1
|
||||
while delta_offset <= #delta do
|
||||
local b = byte(delta, delta_offset)
|
||||
delta_offset = delta_offset + 1
|
||||
|
||||
if band(b, 0x80) ~= 0 then
|
||||
-- Copy from the original file. Each bit represents which optional length/offset
|
||||
-- bits are used.
|
||||
local offset, length = 0, 0
|
||||
|
||||
if band(b, 0x01) ~= 0 then
|
||||
offset, delta_offset = bor(offset, byte(delta, delta_offset)), delta_offset + 1
|
||||
end
|
||||
if band(b, 0x02) ~= 0 then
|
||||
offset, delta_offset = bor(offset, lshift(byte(delta, delta_offset), 8)), delta_offset + 1
|
||||
end
|
||||
if band(b, 0x04) ~= 0 then
|
||||
offset, delta_offset = bor(offset, lshift(byte(delta, delta_offset), 16)), delta_offset + 1
|
||||
end
|
||||
if band(b, 0x08) ~= 0 then
|
||||
offset, delta_offset = bor(offset, lshift(byte(delta, delta_offset), 24)), delta_offset + 1
|
||||
end
|
||||
|
||||
if band(b, 0x10) ~= 0 then
|
||||
length, delta_offset = bor(length, byte(delta, delta_offset)), delta_offset + 1
|
||||
end
|
||||
if band(b, 0x20) ~= 0 then
|
||||
length, delta_offset = bor(length, lshift(byte(delta, delta_offset), 8)), delta_offset + 1
|
||||
end
|
||||
if band(b, 0x40) ~= 0 then
|
||||
length, delta_offset = bor(length, lshift(byte(delta, delta_offset), 16)), delta_offset + 1
|
||||
end
|
||||
if length == 0 then length = 0x10000 end
|
||||
|
||||
parts[n], n = sub(original, offset + 1, offset + length), n + 1
|
||||
elseif b > 0 then
|
||||
-- Copy from the delta. The opcode encodes the length
|
||||
parts[n], n = sub(delta, delta_offset, delta_offset + b - 1), n + 1
|
||||
delta_offset = delta_offset + b
|
||||
else
|
||||
error(("unknown opcode '%02x'"):format(b))
|
||||
end
|
||||
end
|
||||
|
||||
local patched = table.concat(parts)
|
||||
if patched_length ~= #patched then
|
||||
error(("expected patched of size %d, got size %d"):format(patched_length, #patched))
|
||||
end
|
||||
|
||||
return patched
|
||||
end
|
||||
|
||||
--- Unpack a single object, populating the output table
|
||||
--
|
||||
-- @tparam Reader handle The handle to read from
|
||||
-- @tparam { [string] = Object } out The populated data
|
||||
local function unpack_object(handle, out)
|
||||
local c = handle.read8()
|
||||
local ty = band(rshift(c, 4), 7)
|
||||
local size = band(c, 15)
|
||||
local shift = 4
|
||||
while band(c, 0x80) ~= 0 do
|
||||
c = handle.read8()
|
||||
size = size + lshift(band(c, 0x7f), shift)
|
||||
shift = shift + 7
|
||||
end
|
||||
|
||||
local data
|
||||
if ty >= 1 and ty <= 4 then
|
||||
-- commit/tree/blob/tag
|
||||
data = get_data(handle, size)
|
||||
elseif ty == 6 then
|
||||
-- ofs_delta
|
||||
data = get_data(handle, size)
|
||||
error("ofs_delta not yet implemented")
|
||||
|
||||
elseif ty == 7 then
|
||||
-- ref_delta
|
||||
local base_hash = sha_format:format(handle.read(20):byte(1, 20))
|
||||
local delta = get_data(handle, size)
|
||||
|
||||
local original = out[base_hash]
|
||||
if not original then error(("cannot find object %d to apply diff"):format(base_hash)) return end
|
||||
ty = original.ty
|
||||
data = apply_delta(original.data, delta)
|
||||
else
|
||||
error(("unknown object of type '%d'"):format(ty))
|
||||
end
|
||||
|
||||
-- We've got to do these separately. Format doesn't like null bytes
|
||||
local whole = ("%s %d\0"):format(types[ty], #data) .. data
|
||||
local sha = sha(whole)
|
||||
out[sha] = { ty = ty, data = data, sha = sha }
|
||||
end
|
||||
|
||||
local function unpack(handle, progress)
|
||||
local header = handle.read(4)
|
||||
if header ~= "PACK" then error("expected PACK, got " .. header, 0) end
|
||||
|
||||
local version = handle.read32()
|
||||
local entries = handle.read32()
|
||||
|
||||
local out = {}
|
||||
for i = 1, entries do
|
||||
if progress then progress(i, entries) end
|
||||
check_in()
|
||||
|
||||
unpack_object(handle, out)
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local function build_tree(objects, object, prefix, out)
|
||||
if not prefix then prefix = "" end
|
||||
if not out then out = {} end
|
||||
|
||||
local idx = 1
|
||||
|
||||
while idx <= #object do
|
||||
-- dddddd NAME\0<SHA>
|
||||
local _, endidx, mode, name = object:find("^(%x+) ([^%z]+)%z", idx)
|
||||
if not endidx then break end
|
||||
name = prefix .. name
|
||||
|
||||
local sha = object:sub(endidx + 1, endidx + 20):gsub(".", function(x) return ("%02x"):format(string.byte(x)) end)
|
||||
|
||||
local entry = objects[sha]
|
||||
if not entry then error(("cannot find %s %s (%s)"):format(mode, name, sha)) end
|
||||
|
||||
if entry.ty == 3 then
|
||||
out[name] = entry.data
|
||||
elseif entry.ty == 2 then
|
||||
build_tree(objects, entry.data, name .. "/", out)
|
||||
else
|
||||
error("unknown type for " .. name .. " (" .. sha .. "): " .. get_type(entry))
|
||||
end
|
||||
|
||||
idx = endidx + 21
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local function build_commit(objects, sha)
|
||||
local commit = objects[sha]
|
||||
if not commit then error("cannot find commit " .. sha) end
|
||||
if commit.ty ~= 1 then error("Expected commit, got " .. types[commit.ty]) end
|
||||
|
||||
local tree_sha = commit.data:match("tree (%x+)\n")
|
||||
if not tree_sha then error("Cannot find tree from commit") end
|
||||
|
||||
local tree = objects[tree_sha]
|
||||
if not tree then error("cannot find tree " .. tree_sha) end
|
||||
if tree.ty ~= 2 then error("Expected tree, got " .. tree[tree.ty]) end
|
||||
|
||||
return build_tree(objects, tree.data)
|
||||
end
|
||||
|
||||
return {
|
||||
reader = reader,
|
||||
unpack = unpack,
|
||||
build_tree = build_tree,
|
||||
build_commit = build_commit,
|
||||
type = get_type,
|
||||
}
|
||||
end
|
||||
preload["network"] = function(...)
|
||||
local function pkt_line(msg)
|
||||
return ("%04x%s\n"):format(5 + #msg, msg)
|
||||
end
|
||||
|
||||
local function pkt_linef(fmt, ...)
|
||||
return pkt_line(fmt:format(...))
|
||||
end
|
||||
|
||||
local flush_line = "0000"
|
||||
|
||||
local function read_pkt_line(handle)
|
||||
local data = handle.read(4)
|
||||
if data == nil or data == "" then return nil end
|
||||
|
||||
local len = tonumber(data, 16)
|
||||
if len == nil then
|
||||
error(("read_pkt_line: cannot convert %q to a number"):format(data))
|
||||
elseif len == 0 then
|
||||
return false, data
|
||||
else
|
||||
return handle.read(len - 4), data
|
||||
end
|
||||
end
|
||||
|
||||
local function fetch(url, lines, content_type)
|
||||
if type(lines) == "table" then lines = table.concat(lines) end
|
||||
|
||||
local ok, err = http.request(url, lines, {
|
||||
['User-Agent'] = 'CCGit/1.0',
|
||||
['Content-Type'] = content_type,
|
||||
}, true)
|
||||
|
||||
if ok then
|
||||
while true do
|
||||
local event, event_url, param1, param2 = os.pullEvent()
|
||||
if event == "http_success" and event_url == url then
|
||||
return true, param1
|
||||
elseif event == "http_failure" and event_url == url then
|
||||
printError("Cannot fetch " .. url .. ": " .. param1)
|
||||
return false, param2
|
||||
end
|
||||
end
|
||||
else
|
||||
printError("Cannot fetch " .. url .. ": " .. err)
|
||||
return false, nil
|
||||
end
|
||||
end
|
||||
|
||||
local function force_fetch(...)
|
||||
local ok, handle, err_handle = fetch(...)
|
||||
if not ok then
|
||||
if err_handle then
|
||||
print(err_handle.getStatusCode())
|
||||
print(textutils.serialize(err_handle.getResponseHeaders()))
|
||||
print(err_handle.readAll())
|
||||
end
|
||||
error("Cannot fetch", 0)
|
||||
end
|
||||
|
||||
return handle
|
||||
end
|
||||
|
||||
local function receive(handle)
|
||||
local out = {}
|
||||
while true do
|
||||
local line = read_pkt_line(handle)
|
||||
if line == nil then break end
|
||||
out[#out + 1] = line
|
||||
end
|
||||
|
||||
handle.close()
|
||||
return out
|
||||
end
|
||||
|
||||
return {
|
||||
read_pkt_line = read_pkt_line,
|
||||
force_fetch = force_fetch,
|
||||
receive = receive,
|
||||
|
||||
pkt_linef = pkt_linef,
|
||||
flush_line = flush_line,
|
||||
}
|
||||
end
|
||||
preload["deflate"] = function(...)
|
||||
--[[
|
||||
(c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT).
|
||||
|
||||
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.
|
||||
(end license)
|
||||
--]]
|
||||
|
||||
local assert, error, ipairs, pairs, tostring, type, setmetatable, io, math
|
||||
= assert, error, ipairs, pairs, tostring, type, setmetatable, io, math
|
||||
local table_sort, math_max, string_char = table.sort, math.max, string.char
|
||||
local band, lshift, rshift = bit32.band, bit32.lshift, bit32.rshift
|
||||
|
||||
local function make_outstate(outbs)
|
||||
local outstate = {}
|
||||
outstate.outbs = outbs
|
||||
outstate.len = 0
|
||||
outstate.window = {}
|
||||
outstate.window_pos = 1
|
||||
return outstate
|
||||
end
|
||||
|
||||
|
||||
local function output(outstate, byte)
|
||||
local window_pos = outstate.window_pos
|
||||
outstate.outbs(byte)
|
||||
outstate.len = outstate.len + 1
|
||||
outstate.window[window_pos] = byte
|
||||
outstate.window_pos = window_pos % 32768 + 1 -- 32K
|
||||
end
|
||||
|
||||
|
||||
local function noeof(val)
|
||||
return assert(val, 'unexpected end of file')
|
||||
end
|
||||
|
||||
local function memoize(f)
|
||||
return setmetatable({}, {
|
||||
__index = function(self, k)
|
||||
local v = f(k)
|
||||
self[k] = v
|
||||
return v
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-- small optimization (lookup table for powers of 2)
|
||||
local pow2 = memoize(function(n) return 2^n end)
|
||||
|
||||
local function bitstream_from_bytestream(bys)
|
||||
local buf_byte = 0
|
||||
local buf_nbit = 0
|
||||
local o = { type = "bitstream" }
|
||||
|
||||
function o:nbits_left_in_byte()
|
||||
return buf_nbit
|
||||
end
|
||||
|
||||
function o:read(nbits)
|
||||
nbits = nbits or 1
|
||||
while buf_nbit < nbits do
|
||||
local byte = bys()
|
||||
if not byte then return end -- note: more calls also return nil
|
||||
buf_byte = buf_byte + lshift(byte, buf_nbit)
|
||||
buf_nbit = buf_nbit + 8
|
||||
end
|
||||
local bits
|
||||
if nbits == 0 then
|
||||
bits = 0
|
||||
elseif nbits == 32 then
|
||||
bits = buf_byte
|
||||
buf_byte = 0
|
||||
else
|
||||
bits = band(buf_byte, rshift(0xffffffff, 32 - nbits))
|
||||
buf_byte = rshift(buf_byte, nbits)
|
||||
end
|
||||
buf_nbit = buf_nbit - nbits
|
||||
return bits
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
local function get_bitstream(o)
|
||||
if type(o) == "table" and o.type == "bitstream" then
|
||||
return o
|
||||
elseif io.type(o) == 'file' then
|
||||
return bitstream_from_bytestream(function() local sb = o:read(1) if sb then return sb:byte() end end)
|
||||
elseif type(o) == "function" then
|
||||
return bitstream_from_bytestream(o)
|
||||
else
|
||||
error 'unrecognized type'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function get_obytestream(o)
|
||||
local bs
|
||||
if io.type(o) == 'file' then
|
||||
bs = function(sbyte) o:write(string_char(sbyte)) end
|
||||
elseif type(o) == 'function' then
|
||||
bs = o
|
||||
else
|
||||
error('unrecognized type: ' .. tostring(o))
|
||||
end
|
||||
return bs
|
||||
end
|
||||
|
||||
|
||||
local function HuffmanTable(init, is_full)
|
||||
local t = {}
|
||||
if is_full then
|
||||
for val,nbits in pairs(init) do
|
||||
if nbits ~= 0 then
|
||||
t[#t+1] = {val=val, nbits=nbits}
|
||||
end
|
||||
end
|
||||
else
|
||||
for i=1,#init-2,2 do
|
||||
local firstval, nbits, nextval = init[i], init[i+1], init[i+2]
|
||||
if nbits ~= 0 then
|
||||
for val=firstval,nextval-1 do
|
||||
t[#t+1] = {val=val, nbits=nbits}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table_sort(t, function(a,b)
|
||||
return a.nbits == b.nbits and a.val < b.val or a.nbits < b.nbits
|
||||
end)
|
||||
|
||||
-- assign codes
|
||||
local code = 1 -- leading 1 marker
|
||||
local nbits = 0
|
||||
for _, s in ipairs(t) do
|
||||
if s.nbits ~= nbits then
|
||||
code = code * pow2[s.nbits - nbits]
|
||||
nbits = s.nbits
|
||||
end
|
||||
s.code = code
|
||||
code = code + 1
|
||||
end
|
||||
|
||||
local minbits = math.huge
|
||||
local look = {}
|
||||
for _, s in ipairs(t) do
|
||||
minbits = math.min(minbits, s.nbits)
|
||||
look[s.code] = s.val
|
||||
end
|
||||
|
||||
local msb = function(bits, nbits)
|
||||
local res = 0
|
||||
for _ = 1, nbits do
|
||||
res = lshift(res, 1) + band(bits, 1)
|
||||
bits = rshift(bits, 1)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local tfirstcode = memoize(
|
||||
function(bits) return pow2[minbits] + msb(bits, minbits) end)
|
||||
|
||||
function t:read(bs)
|
||||
local code = 1 -- leading 1 marker
|
||||
local nbits = 0
|
||||
while 1 do
|
||||
if nbits == 0 then -- small optimization (optional)
|
||||
code = tfirstcode[noeof(bs:read(minbits))]
|
||||
nbits = nbits + minbits
|
||||
else
|
||||
local b = noeof(bs:read())
|
||||
nbits = nbits + 1
|
||||
code = code * 2 + b -- MSB first
|
||||
end
|
||||
local val = look[code]
|
||||
if val then
|
||||
return val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local function parse_zlib_header(bs)
|
||||
local cm = bs:read(4) -- Compression Method
|
||||
local cinfo = bs:read(4) -- Compression info
|
||||
local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG)
|
||||
local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary)
|
||||
local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level)
|
||||
local cmf = cinfo * 16 + cm -- CMF (Compresion Method and flags)
|
||||
local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs
|
||||
|
||||
if cm ~= 8 then -- not "deflate"
|
||||
error("unrecognized zlib compression method: " .. cm)
|
||||
end
|
||||
if cinfo > 7 then
|
||||
error("invalid zlib window size: cinfo=" .. cinfo)
|
||||
end
|
||||
local window_size = 2^(cinfo + 8)
|
||||
|
||||
if (cmf*256 + flg) % 31 ~= 0 then
|
||||
error("invalid zlib header (bad fcheck sum)")
|
||||
end
|
||||
|
||||
if fdict == 1 then
|
||||
error("FIX:TODO - FDICT not currently implemented")
|
||||
local dictid_ = bs:read(32)
|
||||
end
|
||||
|
||||
return window_size
|
||||
end
|
||||
|
||||
local function parse_huffmantables(bs)
|
||||
local hlit = bs:read(5) -- # of literal/length codes - 257
|
||||
local hdist = bs:read(5) -- # of distance codes - 1
|
||||
local hclen = noeof(bs:read(4)) -- # of code length codes - 4
|
||||
|
||||
local ncodelen_codes = hclen + 4
|
||||
local codelen_init = {}
|
||||
local codelen_vals = {
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
|
||||
for i=1,ncodelen_codes do
|
||||
local nbits = bs:read(3)
|
||||
local val = codelen_vals[i]
|
||||
codelen_init[val] = nbits
|
||||
end
|
||||
local codelentable = HuffmanTable(codelen_init, true)
|
||||
|
||||
local function decode(ncodes)
|
||||
local init = {}
|
||||
local nbits
|
||||
local val = 0
|
||||
while val < ncodes do
|
||||
local codelen = codelentable:read(bs)
|
||||
--FIX:check nil?
|
||||
local nrepeat
|
||||
if codelen <= 15 then
|
||||
nrepeat = 1
|
||||
nbits = codelen
|
||||
elseif codelen == 16 then
|
||||
nrepeat = 3 + noeof(bs:read(2))
|
||||
-- nbits unchanged
|
||||
elseif codelen == 17 then
|
||||
nrepeat = 3 + noeof(bs:read(3))
|
||||
nbits = 0
|
||||
elseif codelen == 18 then
|
||||
nrepeat = 11 + noeof(bs:read(7))
|
||||
nbits = 0
|
||||
else
|
||||
error 'ASSERT'
|
||||
end
|
||||
for _ = 1, nrepeat do
|
||||
init[val] = nbits
|
||||
val = val + 1
|
||||
end
|
||||
end
|
||||
local huffmantable = HuffmanTable(init, true)
|
||||
return huffmantable
|
||||
end
|
||||
|
||||
local nlit_codes = hlit + 257
|
||||
local ndist_codes = hdist + 1
|
||||
|
||||
local littable = decode(nlit_codes)
|
||||
local disttable = decode(ndist_codes)
|
||||
|
||||
return littable, disttable
|
||||
end
|
||||
|
||||
|
||||
local tdecode_len_base
|
||||
local tdecode_len_nextrabits
|
||||
local tdecode_dist_base
|
||||
local tdecode_dist_nextrabits
|
||||
local function parse_compressed_item(bs, outstate, littable, disttable)
|
||||
local val = littable:read(bs)
|
||||
if val < 256 then -- literal
|
||||
output(outstate, val)
|
||||
elseif val == 256 then -- end of block
|
||||
return true
|
||||
else
|
||||
if not tdecode_len_base then
|
||||
local t = {[257]=3}
|
||||
local skip = 1
|
||||
for i=258,285,4 do
|
||||
for j=i,i+3 do t[j] = t[j-1] + skip end
|
||||
if i ~= 258 then skip = skip * 2 end
|
||||
end
|
||||
t[285] = 258
|
||||
tdecode_len_base = t
|
||||
end
|
||||
if not tdecode_len_nextrabits then
|
||||
local t = {}
|
||||
for i=257,285 do
|
||||
local j = math_max(i - 261, 0)
|
||||
t[i] = rshift(j, 2)
|
||||
end
|
||||
t[285] = 0
|
||||
tdecode_len_nextrabits = t
|
||||
end
|
||||
local len_base = tdecode_len_base[val]
|
||||
local nextrabits = tdecode_len_nextrabits[val]
|
||||
local extrabits = bs:read(nextrabits)
|
||||
local len = len_base + extrabits
|
||||
|
||||
if not tdecode_dist_base then
|
||||
local t = {[0]=1}
|
||||
local skip = 1
|
||||
for i=1,29,2 do
|
||||
for j=i,i+1 do t[j] = t[j-1] + skip end
|
||||
if i ~= 1 then skip = skip * 2 end
|
||||
end
|
||||
tdecode_dist_base = t
|
||||
end
|
||||
if not tdecode_dist_nextrabits then
|
||||
local t = {}
|
||||
for i=0,29 do
|
||||
local j = math_max(i - 2, 0)
|
||||
t[i] = rshift(j, 1)
|
||||
end
|
||||
tdecode_dist_nextrabits = t
|
||||
end
|
||||
local dist_val = disttable:read(bs)
|
||||
local dist_base = tdecode_dist_base[dist_val]
|
||||
local dist_nextrabits = tdecode_dist_nextrabits[dist_val]
|
||||
local dist_extrabits = bs:read(dist_nextrabits)
|
||||
local dist = dist_base + dist_extrabits
|
||||
|
||||
for _ = 1,len do
|
||||
local pos = (outstate.window_pos - 1 - dist) % 32768 + 1 -- 32K
|
||||
output(outstate, assert(outstate.window[pos], 'invalid distance'))
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
local function parse_block(bs, outstate)
|
||||
local bfinal = bs:read(1)
|
||||
local btype = bs:read(2)
|
||||
|
||||
local BTYPE_NO_COMPRESSION = 0
|
||||
local BTYPE_FIXED_HUFFMAN = 1
|
||||
local BTYPE_DYNAMIC_HUFFMAN = 2
|
||||
local _BTYPE_RESERVED = 3
|
||||
|
||||
if btype == BTYPE_NO_COMPRESSION then
|
||||
bs:read(bs:nbits_left_in_byte())
|
||||
local len = bs:read(16)
|
||||
local _nlen = noeof(bs:read(16))
|
||||
|
||||
for i=1,len do
|
||||
local by = noeof(bs:read(8))
|
||||
output(outstate, by)
|
||||
end
|
||||
elseif btype == BTYPE_FIXED_HUFFMAN or btype == BTYPE_DYNAMIC_HUFFMAN then
|
||||
local littable, disttable
|
||||
if btype == BTYPE_DYNAMIC_HUFFMAN then
|
||||
littable, disttable = parse_huffmantables(bs)
|
||||
else
|
||||
littable = HuffmanTable {0,8, 144,9, 256,7, 280,8, 288,nil}
|
||||
disttable = HuffmanTable {0,5, 32,nil}
|
||||
end
|
||||
|
||||
repeat
|
||||
local is_done = parse_compressed_item(
|
||||
bs, outstate, littable, disttable)
|
||||
until is_done
|
||||
else
|
||||
error('unrecognized compression type '..btype)
|
||||
end
|
||||
|
||||
return bfinal ~= 0
|
||||
end
|
||||
|
||||
|
||||
local function inflate(t)
|
||||
local bs = get_bitstream(t.input)
|
||||
local outbs = get_obytestream(t.output)
|
||||
local outstate = make_outstate(outbs)
|
||||
|
||||
repeat
|
||||
local is_final = parse_block(bs, outstate)
|
||||
until is_final
|
||||
end
|
||||
|
||||
local function adler32(byte, crc)
|
||||
local s1 = crc % 65536
|
||||
local s2 = (crc - s1) / 65536
|
||||
s1 = (s1 + byte) % 65521
|
||||
s2 = (s2 + s1) % 65521
|
||||
return s2*65536 + s1
|
||||
end -- 65521 is the largest prime smaller than 2^16
|
||||
|
||||
local function inflate_zlib(t)
|
||||
local bs = get_bitstream(t.input)
|
||||
local outbs = get_obytestream(t.output)
|
||||
local disable_crc = t.disable_crc
|
||||
if disable_crc == nil then disable_crc = false end
|
||||
|
||||
local _window_size = parse_zlib_header(bs)
|
||||
|
||||
local data_adler32 = 1
|
||||
|
||||
inflate {
|
||||
input=bs,
|
||||
output = disable_crc and outbs or function(byte)
|
||||
data_adler32 = adler32(byte, data_adler32)
|
||||
outbs(byte)
|
||||
end,
|
||||
len = t.len,
|
||||
}
|
||||
|
||||
bs:read(bs:nbits_left_in_byte())
|
||||
|
||||
local b3 = bs:read(8)
|
||||
local b2 = bs:read(8)
|
||||
local b1 = bs:read(8)
|
||||
local b0 = bs:read(8)
|
||||
local expected_adler32 = ((b3*256 + b2)*256 + b1)*256 + b0
|
||||
|
||||
if not disable_crc then
|
||||
if data_adler32 ~= expected_adler32 then
|
||||
error('invalid compressed data--crc error')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
inflate = inflate,
|
||||
inflate_zlib = inflate_zlib,
|
||||
}
|
||||
end
|
||||
preload["clone"] = function(...)
|
||||
--- Git clone in Lua, from the bottom up
|
||||
--
|
||||
-- http://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/#the_clone_process
|
||||
-- https://github.com/creationix/lua-git
|
||||
|
||||
do -- metis loader
|
||||
local modules = {
|
||||
["metis.argparse"] = "src/metis/argparse.lua",
|
||||
["metis.crypto.sha1"] = "src/metis/crypto/sha1.lua",
|
||||
["metis.timer"] = "src/metis/timer.lua",
|
||||
}
|
||||
package.loaders[#package.loaders + 1] = function(name)
|
||||
local path = modules[name]
|
||||
if not path then return nil, "not a metis module" end
|
||||
|
||||
local local_path = "/.cache/metis/ae11085f261e5b506654162c80d21954c0d54e5e/" .. path
|
||||
if not fs.exists(local_path) then
|
||||
local url = "https://raw.githubusercontent.com/SquidDev-CC/metis/ae11085f261e5b506654162c80d21954c0d54e5e/" .. path
|
||||
local request, err = http.get(url)
|
||||
if not request then return nil, "Cannot download " .. url .. ": " .. err end
|
||||
|
||||
local out = fs.open(local_path, "w")
|
||||
out.write(request.readAll())
|
||||
out.close()
|
||||
|
||||
request.close()
|
||||
end
|
||||
|
||||
|
||||
local fn, err = loadfile(local_path, nil, _ENV)
|
||||
if fn then return fn, local_path else return nil, err end
|
||||
end
|
||||
end
|
||||
|
||||
local network = require "network"
|
||||
local objects = require "objects"
|
||||
|
||||
local url, name = ...
|
||||
if not url or url == "-h" or url == "--help" then error("clone.lua URL [name]", 0) end
|
||||
|
||||
if url:sub(-1) == "/" then url = url:sub(1, -2) end
|
||||
name = name or fs.getName(url):gsub("%.git$", "")
|
||||
|
||||
local destination = shell.resolve(name)
|
||||
if fs.exists(destination) then
|
||||
error(("%q already exists"):format(name), 0)
|
||||
end
|
||||
|
||||
local function report(msg)
|
||||
local last = ""
|
||||
for line in msg:gmatch("[^\n]+") do last = line end
|
||||
if replaceLine then
|
||||
term.setCursorPos(1, select(2, term.getCursorPos()))
|
||||
term.clearLine()
|
||||
term.write(last)
|
||||
else
|
||||
print(last)
|
||||
end
|
||||
end
|
||||
|
||||
local head
|
||||
do -- Request a list of all refs
|
||||
report("Cloning from " .. url)
|
||||
|
||||
local handle = network.force_fetch(url .. "/info/refs?service=git-upload-pack")
|
||||
local res = network.receive(handle)
|
||||
|
||||
local sha_ptrn = ("%x"):rep(40)
|
||||
|
||||
local caps = {}
|
||||
local refs = {}
|
||||
for i = 1, #res do
|
||||
local line = res[i]
|
||||
if line ~= false and line:sub(1, 1) ~= "#" then
|
||||
local sha, name = line:match("(" .. sha_ptrn .. ") ([^%z\n]+)")
|
||||
if sha and name then
|
||||
refs[name] = sha
|
||||
|
||||
local capData = line:match("%z([^\n]+)\n")
|
||||
if capData then
|
||||
for cap in (capData .. " "):gmatch("%S+") do
|
||||
local eq = cap:find("=")
|
||||
if eq then
|
||||
caps[cap:sub(1, eq - 1)] = cap:sub(eq + 1)
|
||||
else
|
||||
caps[cap] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
printError("Unexpected line: " .. line)
|
||||
end
|
||||
end
|
||||
end
|
||||
head = refs['HEAD'] or refs['refs/heads/master'] or error("Cannot find master", 0)
|
||||
|
||||
if not caps['shallow'] then error("Server does not support shallow fetching", 0) end
|
||||
|
||||
-- TODO: Handle both. We don't even need the side-band really?
|
||||
if not caps['side-band-64k'] then error("Server does not support side band", 0) end
|
||||
end
|
||||
|
||||
do -- Now actually perform the clone
|
||||
local handle = network.force_fetch(url .. "/git-upload-pack", {
|
||||
network.pkt_linef("want %s side-band-64k shallow", head),
|
||||
network.pkt_linef("deepen 1"),
|
||||
network.flush_line,
|
||||
network.pkt_linef("done"),
|
||||
}, "application/x-git-upload-pack-request")
|
||||
|
||||
local pack, head = {}, nil
|
||||
while true do
|
||||
local line = network.read_pkt_line(handle)
|
||||
if line == nil then break end
|
||||
|
||||
if line == false or line == "NAK\n" then
|
||||
-- Skip
|
||||
elseif line:byte(1) == 1 then
|
||||
table.insert(pack, line:sub(2))
|
||||
elseif line:byte(1) == 2 or line:byte(1) == 3 then
|
||||
report(line:sub(2):gsub("\r", "\n"))
|
||||
elseif line:find("^shallow ") then
|
||||
head = line:sub(#("shallow ") + 1)
|
||||
else
|
||||
printError("Unknown line: " .. tostring(line))
|
||||
end
|
||||
end
|
||||
handle.close()
|
||||
|
||||
local stream = objects.reader(table.concat(pack))
|
||||
local objs = objects.unpack(stream, function(x, n)
|
||||
report(("Extracting %d/%d (%.2f%%)"):format(x, n, x/n*100))
|
||||
end)
|
||||
stream.close()
|
||||
|
||||
if not head then error("Cannot find HEAD commit", 0) end
|
||||
|
||||
for k, v in pairs(objects.build_commit(objs, head)) do
|
||||
local out = fs.open(fs.combine(destination, fs.combine(k, "")), "wb")
|
||||
out.write(v)
|
||||
out.close()
|
||||
end
|
||||
end
|
||||
|
||||
report(("Cloned to %q"):format(name))
|
||||
print()
|
||||
end
|
||||
return preload["clone"](...)
|
109
bin/gist
Normal file
109
bin/gist
Normal file
|
@ -0,0 +1,109 @@
|
|||
-- gist.lua - Gist client for ComputerCraft
|
||||
-- Made by JackMacWindows for CraftOS-PC and CC: Tweaked
|
||||
|
||||
if not http then
|
||||
printError("Gist requires http API")
|
||||
if _G.config ~= nil then printError("Set http_enable to true in the CraftOS-PC configuration")
|
||||
else printError("Set http_enable to true in ComputerCraft's configuration") end
|
||||
return 2
|
||||
end
|
||||
|
||||
local gist = require "cc.http.gist"
|
||||
|
||||
local args = { ... }
|
||||
|
||||
local function readFile(filename, files, isEditing)
|
||||
if fs.isDir(shell.resolve(filename)) then
|
||||
for _, v in ipairs(fs.list(shell.resolve(filename))) do if readFile(fs.combine(filename, v), files, isEditing) then return true end end
|
||||
else
|
||||
if files[fs.getName(filename)] then print("Cannot upload files with duplicate names.") return true end
|
||||
local file = fs.open(shell.resolve(filename), "rb")
|
||||
if file == nil then
|
||||
if not isEditing then print("Could not read " .. filename .. ".") return true
|
||||
else files[fs.getName(filename)] = textutils.json_null end
|
||||
else
|
||||
files[fs.getName(filename)] = file.readAll()
|
||||
file.close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getFiles(isEditing)
|
||||
local files = {}
|
||||
local i = isEditing and 3 or 2
|
||||
while args[i] ~= nil and args[i] ~= "--" do
|
||||
if readFile(args[i], files, isEditing) then return nil end
|
||||
i = i + 1
|
||||
end
|
||||
if args[i] == "--" then return files, table.concat({ table.unpack(args, i + 1) }, " ") end
|
||||
return files
|
||||
end
|
||||
|
||||
local function setTextColor(c) if term.isColor() then term.setTextColor(c) elseif c == colors.white or c == colors.yellow then term.setTextColor(colors.white) else term.setTextColor(colors.lightGray) end end
|
||||
|
||||
local helpstr = "Usages:\ngist put <files...> [-- description...]\ngist edit <id> <files...> [-- description]\ngist delete <id>\ngist get <id> <filename>\ngist run <id> [arguments...]\ngist info <id>"
|
||||
|
||||
if #args < 2 then
|
||||
print(helpstr)
|
||||
return 1
|
||||
end
|
||||
|
||||
if args[1] == "get" then
|
||||
if #args < 3 then print(helpstr) return 1 end
|
||||
if args[3]:sub(#args[3]) == "/" or fs.isDir(shell.resolve(args[3])) then
|
||||
fs.makeDir(shell.resolve(args[3]))
|
||||
local files, err = gist.getAll(args[2], write)
|
||||
if files == nil then printError(err) return 3 end
|
||||
for k, v in pairs(files) do
|
||||
local file = fs.open(shell.resolve(fs.combine(args[3], k)), "wb")
|
||||
file.write(v)
|
||||
file.close()
|
||||
end
|
||||
print("Downloaded all files to " .. shell.resolve(args[3]))
|
||||
else
|
||||
local data, err = gist.get(args[2], write)
|
||||
if data == nil then printError(err) return 3 end
|
||||
local file = fs.open(shell.resolve(args[3]), "wb")
|
||||
file.write(data)
|
||||
file.close()
|
||||
print("Downloaded as " .. shell.resolve(args[3]))
|
||||
end
|
||||
elseif args[1] == "run" then
|
||||
return gist.run(args[2], write, table.unpack(args, 3))
|
||||
elseif args[1] == "put" then
|
||||
local files, description = getFiles(false)
|
||||
if files == nil then return end
|
||||
local id, html_url = gist.put(files, description, nil, true)
|
||||
if id ~= nil then print("Uploaded as " .. html_url .. "\nRun 'gist get " .. id .. "' to download anywhere")
|
||||
else printError(html_url) return 3 end
|
||||
elseif args[1] == "info" then
|
||||
local tab, err = gist.info(args[2], write)
|
||||
if tab == nil then printError(err) return 3 end
|
||||
setTextColor(colors.yellow)
|
||||
write("Description: ")
|
||||
setTextColor(colors.white)
|
||||
print(tab.description)
|
||||
setTextColor(colors.yellow)
|
||||
write("Author: ")
|
||||
setTextColor(colors.white)
|
||||
print(tab.author)
|
||||
setTextColor(colors.yellow)
|
||||
write("Revisions: ")
|
||||
setTextColor(colors.white)
|
||||
print(tab.revisionCount)
|
||||
setTextColor(colors.yellow)
|
||||
print("Files in this Gist:")
|
||||
setTextColor(colors.white)
|
||||
textutils.tabulate(tab.files)
|
||||
elseif args[1] == "edit" then
|
||||
if #args < 3 then print(helpstr) return 1 end
|
||||
local files, description = getFiles(true)
|
||||
if files == nil then return 2 end
|
||||
if not description then description = gist.info(args[2], write).description end
|
||||
local id, html_url = gist.put(files, description, args[2], true)
|
||||
if id then print("Uploaded as " .. html_url .. "\nRun 'gist get " .. args[2] .. "' to download anywhere")
|
||||
else printError(html_url) return 3 end
|
||||
elseif args[1] == "delete" then
|
||||
local ok, err = gist.delete(args[2], true)
|
||||
if ok then print("The requested Gist has been deleted.") else printError(err) return 3 end
|
||||
else print(helpstr) return 1 end
|
94
bin/gps
Normal file
94
bin/gps
Normal file
|
@ -0,0 +1,94 @@
|
|||
local function printUsage()
|
||||
local programName = "gps"
|
||||
print("Usages:")
|
||||
print(programName .. " host")
|
||||
print(programName .. " host <x> <y> <z>")
|
||||
print(programName .. " locate")
|
||||
end
|
||||
|
||||
local tArgs = { ... }
|
||||
if #tArgs < 1 then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
local sCommand = tArgs[1]
|
||||
if sCommand == "locate" then
|
||||
-- "gps locate"
|
||||
-- Just locate this computer (this will print the results)
|
||||
gps.locate(2, true)
|
||||
|
||||
elseif sCommand == "host" then
|
||||
-- "gps host"
|
||||
-- Act as a GPS host
|
||||
if pocket then
|
||||
print("GPS Hosts must be stationary")
|
||||
return
|
||||
end
|
||||
|
||||
-- Find a modem
|
||||
local sModemSide = nil
|
||||
for _, sSide in ipairs(rs.getSides()) do
|
||||
if peripheral.getType(sSide) == "modem" and peripheral.call(sSide, "isWireless") then
|
||||
sModemSide = sSide
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if sModemSide == nil then
|
||||
print("No wireless modems found. 1 required.")
|
||||
return
|
||||
end
|
||||
|
||||
-- Determine position
|
||||
local x, y, z
|
||||
if #tArgs >= 4 then
|
||||
-- Position is manually specified
|
||||
x = tonumber(tArgs[2])
|
||||
y = tonumber(tArgs[3])
|
||||
z = tonumber(tArgs[4])
|
||||
if x == nil or y == nil or z == nil then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
print("Position is " .. x .. "," .. y .. "," .. z)
|
||||
else
|
||||
-- Position is to be determined using locate
|
||||
x, y, z = gps.locate(2, true)
|
||||
if x == nil then
|
||||
print("Run \"gps host <x> <y> <z>\" to set position manually")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Open a channel
|
||||
local modem = peripheral.wrap(sModemSide)
|
||||
print("Opening channel on modem " .. sModemSide)
|
||||
modem.open(gps.CHANNEL_GPS)
|
||||
|
||||
-- Serve requests indefinately
|
||||
local nServed = 0
|
||||
while true do
|
||||
local e, p1, p2, p3, p4, p5 = os.pullEvent("modem_message")
|
||||
if e == "modem_message" then
|
||||
-- We received a message from a modem
|
||||
local sSide, sChannel, sReplyChannel, sMessage, nDistance = p1, p2, p3, p4, p5
|
||||
if sSide == sModemSide and sChannel == gps.CHANNEL_GPS and sMessage == "PING" and nDistance then
|
||||
-- We received a ping message on the GPS channel, send a response
|
||||
modem.transmit(sReplyChannel, gps.CHANNEL_GPS, { x, y, z })
|
||||
|
||||
-- Print the number of requests handled
|
||||
nServed = nServed + 1
|
||||
if nServed > 1 then
|
||||
local _, y = term.getCursorPos()
|
||||
term.setCursorPos(1, y - 1)
|
||||
end
|
||||
print(nServed .. " GPS requests served")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- "gps somethingelse"
|
||||
-- Error
|
||||
printUsage()
|
||||
end
|
18
bin/hostname
Normal file
18
bin/hostname
Normal file
|
@ -0,0 +1,18 @@
|
|||
local tArgs = { ... }
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo("net", kernel.getHostname())
|
||||
else
|
||||
if tArgs[1] == "--set" then
|
||||
if #tArgs >= 2 then
|
||||
local hostname = tArgs[2]
|
||||
for i,v in ipairs(tArgs) do
|
||||
if not (i == 1 or i == 2) then
|
||||
hostname = hostname .. tArgs[i]
|
||||
end
|
||||
end
|
||||
kernel.setHostname(hostname)
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("hostname","Arguments not specified")
|
||||
end
|
||||
end
|
37
bin/list
Normal file
37
bin/list
Normal file
|
@ -0,0 +1,37 @@
|
|||
local tArgs = { ... }
|
||||
|
||||
-- Get all the files in the directory
|
||||
local sDir = shell.dir()
|
||||
if tArgs[1] ~= nil then
|
||||
sDir = shell.resolve(tArgs[1])
|
||||
end
|
||||
|
||||
if not fs.isDir(sDir) then
|
||||
printError("Not a directory")
|
||||
return
|
||||
end
|
||||
|
||||
-- Sort into dirs/files, and calculate column count
|
||||
local tAll = fs.list(sDir)
|
||||
local tFiles = {}
|
||||
local tDirs = {}
|
||||
|
||||
local bShowHidden = settings.get("list.show_hidden")
|
||||
for _, sItem in pairs(tAll) do
|
||||
if bShowHidden or string.sub(sItem, 1, 1) ~= "." then
|
||||
local sPath = fs.combine(sDir, sItem)
|
||||
if fs.isDir(sPath) then
|
||||
table.insert(tDirs, sItem)
|
||||
else
|
||||
table.insert(tFiles, sItem)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(tDirs)
|
||||
table.sort(tFiles)
|
||||
|
||||
if term.isColour() then
|
||||
textutils.pagedTabulate(colors.green, tDirs, colors.white, tFiles)
|
||||
else
|
||||
textutils.pagedTabulate(colors.lightGray, tDirs, colors.white, tFiles)
|
||||
end
|
102
bin/lsh
Normal file
102
bin/lsh
Normal file
|
@ -0,0 +1,102 @@
|
|||
local bRunning = true
|
||||
local tCommandHistory = {}
|
||||
local tEnv = {
|
||||
["exit"] = function()
|
||||
bRunning = false
|
||||
end,
|
||||
["_echo"] = function( ... )
|
||||
return ...
|
||||
end,
|
||||
}
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
setmetatable( tEnv, { __index = _ENV } )
|
||||
|
||||
local label = os.getComputerLabel() or os.getComputerID()
|
||||
|
||||
print( "lsh - The Lua interpreter shell" )
|
||||
print("Call exit() to quit.")
|
||||
term.setTextColour( colours.white )
|
||||
|
||||
while bRunning do
|
||||
if security.getActiveUserStatus() then
|
||||
term.setTextColour( colours.lime )
|
||||
else
|
||||
term.setTextColour( colours.orange )
|
||||
end
|
||||
write( _activeUser )
|
||||
term.setTextColour( colours.lightGrey )
|
||||
write( "@" )
|
||||
term.setTextColour( colours.lightBlue )
|
||||
write( label )
|
||||
term.setTextColour( colours.lightGrey )
|
||||
write( "/" )
|
||||
term.setTextColour( colours.lightBlue )
|
||||
write( shell.dir() )
|
||||
if security.getActiveUserStatus() then
|
||||
term.setTextColour( colours.lime )
|
||||
else
|
||||
term.setTextColour( colours.orange )
|
||||
end
|
||||
write( " % " )
|
||||
|
||||
term.setTextColour( colours.white )
|
||||
|
||||
local s = read( nil, tCommandHistory, function( sLine )
|
||||
local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.]+$" )
|
||||
if nStartPos then
|
||||
sLine = string.sub( sLine, nStartPos )
|
||||
end
|
||||
if #sLine > 0 then
|
||||
return textutils.complete( sLine, tEnv )
|
||||
end
|
||||
return nil
|
||||
end )
|
||||
term.setTextColour( colours.lightGrey )
|
||||
table.insert( tCommandHistory, s )
|
||||
|
||||
local nForcePrint = 0
|
||||
local func, e = load( s, "lua", "t", tEnv )
|
||||
local func2, e2 = load( "return _echo("..s..");", "lua", "t", tEnv )
|
||||
if not func then
|
||||
if func2 then
|
||||
func = func2
|
||||
e = nil
|
||||
nForcePrint = 1
|
||||
end
|
||||
else
|
||||
if func2 then
|
||||
func = func2
|
||||
end
|
||||
end
|
||||
|
||||
if func then
|
||||
local tResults = { pcall( func ) }
|
||||
if tResults[1] then
|
||||
local n = 1
|
||||
while (tResults[n + 1] ~= nil) or (n <= nForcePrint) do
|
||||
local value = tResults[ n + 1 ]
|
||||
if type( value ) == "table" then
|
||||
local ok, serialised = pcall( textutils.serialise, value )
|
||||
if ok then
|
||||
print( serialised )
|
||||
else
|
||||
print( tostring( value ) )
|
||||
end
|
||||
else
|
||||
print( tostring( value ) )
|
||||
end
|
||||
n = n + 1
|
||||
end
|
||||
else
|
||||
printError( tResults[2] )
|
||||
end
|
||||
else
|
||||
printError( e )
|
||||
end
|
||||
|
||||
end
|
7
bin/man
Normal file
7
bin/man
Normal file
|
@ -0,0 +1,7 @@
|
|||
local tArgs = {...}
|
||||
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo("man", "type 'ls system/man-pages' or 'manpages'")
|
||||
else
|
||||
kerneldraw.printAppInfo("man", man.findManual(tArgs[1]))
|
||||
end
|
13
bin/manedit
Normal file
13
bin/manedit
Normal file
|
@ -0,0 +1,13 @@
|
|||
local tArgs = {...}
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo("manedit", "filename not specified")
|
||||
return
|
||||
end
|
||||
|
||||
shell.run("/bin/nano /etc/manuals/"..tArgs[1])
|
1
bin/manpages
Normal file
1
bin/manpages
Normal file
|
@ -0,0 +1 @@
|
|||
shell.run("/bin/nano /etc/manuals")
|
18
bin/mkdir
Normal file
18
bin/mkdir
Normal file
|
@ -0,0 +1,18 @@
|
|||
local tArgs = { ... }
|
||||
|
||||
if #tArgs < 1 then
|
||||
local programName = "mkdir"
|
||||
print("Usage: " .. programName .. " <paths>")
|
||||
return
|
||||
end
|
||||
|
||||
for _, v in ipairs(tArgs) do
|
||||
local sNewDir = shell.resolve(v)
|
||||
if fs.exists(sNewDir) and not fs.isDir(sNewDir) then
|
||||
printError(v .. ": Destination exists")
|
||||
elseif fs.isReadOnly(sNewDir) then
|
||||
printError(v .. ": Access denied")
|
||||
else
|
||||
fs.makeDir(sNewDir)
|
||||
end
|
||||
end
|
95
bin/monitor
Normal file
95
bin/monitor
Normal file
|
@ -0,0 +1,95 @@
|
|||
local function printUsage()
|
||||
local programName = "monitor"
|
||||
print("Usage:")
|
||||
print(" " .. programName .. " <name> <program> <arguments>")
|
||||
print(" " .. programName .. " scale <name> <scale>")
|
||||
return
|
||||
end
|
||||
|
||||
local tArgs = { ... }
|
||||
if #tArgs < 2 or tArgs[1] == "scale" and #tArgs < 3 then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
if tArgs[1] == "scale" then
|
||||
local sName = tArgs[2]
|
||||
if peripheral.getType(sName) ~= "monitor" then
|
||||
print("No monitor named " .. sName)
|
||||
return
|
||||
end
|
||||
|
||||
local nRes = tonumber(tArgs[3])
|
||||
if nRes == nil or nRes < 0.5 or nRes > 5 then
|
||||
print("Invalid scale: " .. tArgs[3])
|
||||
return
|
||||
end
|
||||
|
||||
peripheral.call(sName, "setTextScale", nRes)
|
||||
return
|
||||
end
|
||||
|
||||
local sName = tArgs[1]
|
||||
if peripheral.getType(sName) ~= "monitor" then
|
||||
print("No monitor named " .. sName)
|
||||
return
|
||||
end
|
||||
|
||||
local sProgram = tArgs[2]
|
||||
|
||||
local sPath = shell.resolveProgram(sProgram)
|
||||
if sPath == nil then
|
||||
print("No such program: " .. sProgram)
|
||||
return
|
||||
end
|
||||
|
||||
print("Running " .. sProgram .. " on monitor " .. sName)
|
||||
|
||||
local monitor = peripheral.wrap(sName)
|
||||
local previousTerm = term.redirect(monitor)
|
||||
|
||||
local co = coroutine.create(function()
|
||||
(shell.execute or shell.run)(sProgram, table.unpack(tArgs, 3))
|
||||
end)
|
||||
|
||||
local function resume(...)
|
||||
local ok, param = coroutine.resume(co, ...)
|
||||
if not ok then
|
||||
printError(param)
|
||||
end
|
||||
return param
|
||||
end
|
||||
|
||||
local timers = {}
|
||||
|
||||
local ok, param = pcall(function()
|
||||
local sFilter = resume()
|
||||
while coroutine.status(co) ~= "dead" do
|
||||
local tEvent = table.pack(os.pullEventRaw())
|
||||
if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == "terminate" then
|
||||
sFilter = resume(table.unpack(tEvent, 1, tEvent.n))
|
||||
end
|
||||
if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then
|
||||
if tEvent[1] == "monitor_touch" and tEvent[2] == sName then
|
||||
timers[os.startTimer(0.1)] = { tEvent[3], tEvent[4] }
|
||||
sFilter = resume("mouse_click", 1, table.unpack(tEvent, 3, tEvent.n))
|
||||
end
|
||||
end
|
||||
if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "term_resize") then
|
||||
if tEvent[1] == "monitor_resize" and tEvent[2] == sName then
|
||||
sFilter = resume("term_resize")
|
||||
end
|
||||
end
|
||||
if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then
|
||||
if tEvent[1] == "timer" and timers[tEvent[2]] then
|
||||
sFilter = resume("mouse_up", 1, table.unpack(timers[tEvent[2]], 1, 2))
|
||||
timers[tEvent[2]] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
term.redirect(previousTerm)
|
||||
if not ok then
|
||||
printError(param)
|
||||
end
|
23
bin/mount
Normal file
23
bin/mount
Normal file
|
@ -0,0 +1,23 @@
|
|||
if mounter == nil then error("Mounting directories is not supported in vanilla mode.") end
|
||||
local args = { ... }
|
||||
|
||||
if args[2] ~= nil then
|
||||
local ro = nil
|
||||
if args[3] == "readOnly" or args[3] == "true" then ro = true
|
||||
elseif args[3] == "false" then ro = false end
|
||||
if config.get("showMountPrompt") then print("A prompt will appear asking to confirm mounting. Press Allow to continue mounting.") end
|
||||
if not mounter.mount(args[1], args[2], ro) then printError("Could not mount") end
|
||||
elseif args[1] == "--help" then
|
||||
term.setTextColor(colors.red)
|
||||
print("Usage: mount <name> <path> [readOnly]")
|
||||
print(" mount --help")
|
||||
print(" mount")
|
||||
term.setTextColor(colors.white)
|
||||
else
|
||||
local mounts = mounter.list()
|
||||
print("/ on computer/" .. os.getComputerID())
|
||||
for k,v in pairs(mounts) do
|
||||
write("/" .. k .. " on " .. (#v == 1 and v[1] or "(\n " .. table.concat(v, ",\n ") .. "\n)"))
|
||||
if mounter.isReadOnly(k) then print(" (read-only)") else print() end
|
||||
end
|
||||
end
|
47
bin/mv
Normal file
47
bin/mv
Normal file
|
@ -0,0 +1,47 @@
|
|||
local tArgs = { ... }
|
||||
if #tArgs < 2 then
|
||||
local programName = "mv"
|
||||
print("Usage: " .. programName .. " <source> <destination>")
|
||||
return
|
||||
end
|
||||
|
||||
local sSource = shell.resolve(tArgs[1])
|
||||
local sDest = shell.resolve(tArgs[2])
|
||||
local tFiles = fs.find(sSource)
|
||||
|
||||
local function sanity_checks(source, dest)
|
||||
if fs.exists(dest) then
|
||||
printError("Destination exists")
|
||||
return false
|
||||
elseif fs.isReadOnly(dest) then
|
||||
printError("Destination is read-only")
|
||||
return false
|
||||
elseif fs.isDriveRoot(source) then
|
||||
printError("Cannot move mount /" .. source)
|
||||
return false
|
||||
elseif fs.isReadOnly(source) then
|
||||
printError("Cannot move read-only file /" .. source)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if #tFiles > 0 then
|
||||
for _, sFile in ipairs(tFiles) do
|
||||
if fs.isDir(sDest) then
|
||||
local dest = fs.combine(sDest, fs.getName(sFile))
|
||||
if sanity_checks(sFile, dest) then
|
||||
fs.move(sFile, dest)
|
||||
end
|
||||
elseif #tFiles == 1 then
|
||||
if sanity_checks(sFile, sDest) then
|
||||
fs.move(sFile, sDest)
|
||||
end
|
||||
else
|
||||
printError("Cannot overwrite file multiple times")
|
||||
return
|
||||
end
|
||||
end
|
||||
else
|
||||
printError("No matching files")
|
||||
end
|
772
bin/nano
Normal file
772
bin/nano
Normal file
|
@ -0,0 +1,772 @@
|
|||
-- Get file to edit
|
||||
local tArgs = { ... }
|
||||
if #tArgs == 0 then
|
||||
print( "Usage: nano <path>" )
|
||||
return
|
||||
end
|
||||
|
||||
-- Error checking
|
||||
local sPath = shell.resolve( tArgs[1] )
|
||||
local bReadOnly = fs.isReadOnly( sPath )
|
||||
if fs.exists( sPath ) and fs.isDir( sPath ) then
|
||||
print( "Cannot edit a directory." )
|
||||
return
|
||||
end
|
||||
|
||||
if bReadOnly and not security.getSU() then
|
||||
-- prevent users from seeing unauthorized code
|
||||
-- they should only be able to see their own files and ones in /var/log
|
||||
exception.throw("SecurityException", sPath)
|
||||
return
|
||||
end
|
||||
|
||||
local x,y = 1,1
|
||||
local w,h = term.getSize()
|
||||
local scrollX, scrollY = 0,0
|
||||
|
||||
local tLines = {}
|
||||
local bRunning = true
|
||||
|
||||
-- Colours
|
||||
local highlightColour, keywordColour, commentColour, textColour, bgColour
|
||||
if term.isColour() then
|
||||
bgColour = colours.black
|
||||
textColour = colours.white
|
||||
highlightColour = colours.yellow
|
||||
keywordColour = colours.yellow
|
||||
commentColour = colours.green
|
||||
stringColour = colours.red
|
||||
else
|
||||
bgColour = colours.black
|
||||
textColour = colours.white
|
||||
highlightColour = colours.white
|
||||
keywordColour = colours.white
|
||||
commentColour = colours.white
|
||||
stringColour = colours.white
|
||||
end
|
||||
|
||||
-- Menus
|
||||
local bMenu = false
|
||||
local nMenuItem = 1
|
||||
local tMenuItems = {}
|
||||
if not bReadOnly then
|
||||
table.insert( tMenuItems, "Save" )
|
||||
end
|
||||
if shell.openTab then
|
||||
table.insert( tMenuItems, "Run" )
|
||||
end
|
||||
if peripheral.find( "printer" ) then
|
||||
table.insert( tMenuItems, "Print" )
|
||||
end
|
||||
table.insert( tMenuItems, "Exit" )
|
||||
|
||||
local sStatus = "Press Ctrl to access menu"
|
||||
if string.len( sStatus ) > w - 5 then
|
||||
sStatus = "Press Ctrl for menu"
|
||||
end
|
||||
|
||||
local function load( _sPath )
|
||||
tLines = {}
|
||||
if fs.exists( _sPath ) then
|
||||
local file = io.open( _sPath, "r" )
|
||||
local sLine = file:read()
|
||||
while sLine do
|
||||
table.insert( tLines, sLine )
|
||||
sLine = file:read()
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
if #tLines == 0 then
|
||||
table.insert( tLines, "" )
|
||||
end
|
||||
end
|
||||
|
||||
local function save( _sPath )
|
||||
-- Create intervening folder
|
||||
local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() )
|
||||
if not fs.exists( sDir ) then
|
||||
fs.makeDir( sDir )
|
||||
end
|
||||
|
||||
-- Save
|
||||
local file = nil
|
||||
local function innerSave()
|
||||
file = fs.open( _sPath, "w" )
|
||||
if file then
|
||||
for n, sLine in ipairs( tLines ) do
|
||||
file.write( sLine .. "\n" )
|
||||
end
|
||||
else
|
||||
error( "Failed to open ".._sPath )
|
||||
end
|
||||
end
|
||||
|
||||
local ok, err = pcall( innerSave )
|
||||
if file then
|
||||
file.close()
|
||||
end
|
||||
return ok, err
|
||||
end
|
||||
|
||||
local tKeywords = {
|
||||
["and"] = true,
|
||||
["break"] = true,
|
||||
["do"] = true,
|
||||
["else"] = true,
|
||||
["elseif"] = true,
|
||||
["end"] = true,
|
||||
["false"] = true,
|
||||
["for"] = true,
|
||||
["function"] = true,
|
||||
["if"] = true,
|
||||
["in"] = true,
|
||||
["local"] = true,
|
||||
["nil"] = true,
|
||||
["not"] = true,
|
||||
["or"] = true,
|
||||
["repeat"] = true,
|
||||
["return"] = true,
|
||||
["then"] = true,
|
||||
["true"] = true,
|
||||
["until"]= true,
|
||||
["while"] = true,
|
||||
}
|
||||
|
||||
local function tryWrite( sLine, regex, colour )
|
||||
local match = string.match( sLine, regex )
|
||||
if match then
|
||||
if type(colour) == "number" then
|
||||
term.setTextColour( colour )
|
||||
else
|
||||
term.setTextColour( colour(match) )
|
||||
end
|
||||
term.write( match )
|
||||
term.setTextColour( textColour )
|
||||
return string.sub( sLine, string.len(match) + 1 )
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function writeHighlighted( sLine )
|
||||
while string.len(sLine) > 0 do
|
||||
sLine =
|
||||
tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or
|
||||
tryWrite( sLine, "^%-%-.*", commentColour ) or
|
||||
tryWrite( sLine, "^\".-[^\\]\"", stringColour ) or
|
||||
tryWrite( sLine, "^\'.-[^\\]\'", stringColour ) or
|
||||
tryWrite( sLine, "^%[%[.-%]%]", stringColour ) or
|
||||
tryWrite( sLine, "^[%w_]+", function( match )
|
||||
if tKeywords[ match ] then
|
||||
return keywordColour
|
||||
end
|
||||
return textColour
|
||||
end ) or
|
||||
tryWrite( sLine, "^[^%w_]", textColour )
|
||||
end
|
||||
end
|
||||
|
||||
local tCompletions
|
||||
local nCompletion
|
||||
|
||||
local tCompleteEnv = _ENV
|
||||
local function complete( sLine )
|
||||
local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.]+$" )
|
||||
if nStartPos then
|
||||
sLine = string.sub( sLine, nStartPos )
|
||||
end
|
||||
if #sLine > 0 then
|
||||
return textutils.complete( sLine, tCompleteEnv )
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function recomplete()
|
||||
local sLine = tLines[y]
|
||||
if not bMenu and not bReadOnly and x == string.len(sLine) + 1 then
|
||||
tCompletions = complete( sLine )
|
||||
if tCompletions and #tCompletions > 0 then
|
||||
nCompletion = 1
|
||||
else
|
||||
nCompletion = nil
|
||||
end
|
||||
else
|
||||
tCompletions = nil
|
||||
nCompletion = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function writeCompletion( sLine )
|
||||
if nCompletion then
|
||||
local sCompletion = tCompletions[ nCompletion ]
|
||||
term.setTextColor( colours.white )
|
||||
term.setBackgroundColor( colours.grey )
|
||||
term.write( sCompletion )
|
||||
term.setTextColor( textColour )
|
||||
term.setBackgroundColor( bgColour )
|
||||
end
|
||||
end
|
||||
|
||||
local function redrawText()
|
||||
local cursorX, cursorY = x, y
|
||||
for y=1,h-1 do
|
||||
term.setCursorPos( 1 - scrollX, y )
|
||||
term.clearLine()
|
||||
|
||||
local sLine = tLines[ y + scrollY ]
|
||||
if sLine ~= nil then
|
||||
writeHighlighted( sLine )
|
||||
if cursorY == y and cursorX == #sLine + 1 then
|
||||
writeCompletion()
|
||||
end
|
||||
end
|
||||
end
|
||||
term.setCursorPos( x - scrollX, y - scrollY )
|
||||
end
|
||||
|
||||
local function redrawLine(_nY)
|
||||
local sLine = tLines[_nY]
|
||||
if sLine then
|
||||
term.setCursorPos( 1 - scrollX, _nY - scrollY )
|
||||
term.clearLine()
|
||||
writeHighlighted( sLine )
|
||||
if _nY == y and x == #sLine + 1 then
|
||||
writeCompletion()
|
||||
end
|
||||
term.setCursorPos( x - scrollX, _nY - scrollY )
|
||||
end
|
||||
end
|
||||
|
||||
local function redrawMenu()
|
||||
-- Clear line
|
||||
term.setCursorPos( 1, h )
|
||||
term.clearLine()
|
||||
|
||||
-- Draw line numbers
|
||||
term.setCursorPos( w - string.len( "Ln "..y ) + 1, h )
|
||||
term.setTextColour( highlightColour )
|
||||
term.write( "Ln " )
|
||||
term.setTextColour( textColour )
|
||||
term.write( y )
|
||||
|
||||
term.setCursorPos( 1, h )
|
||||
if bMenu then
|
||||
-- Draw menu
|
||||
term.setTextColour( textColour )
|
||||
for nItem,sItem in pairs( tMenuItems ) do
|
||||
if nItem == nMenuItem then
|
||||
term.setTextColour( highlightColour )
|
||||
term.write( "[" )
|
||||
term.setTextColour( textColour )
|
||||
term.write( sItem )
|
||||
term.setTextColour( highlightColour )
|
||||
term.write( "]" )
|
||||
term.setTextColour( textColour )
|
||||
else
|
||||
term.write( " "..sItem.." " )
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Draw status
|
||||
term.setTextColour( highlightColour )
|
||||
term.write( sStatus )
|
||||
term.setTextColour( textColour )
|
||||
end
|
||||
|
||||
-- Reset cursor
|
||||
term.setCursorPos( x - scrollX, y - scrollY )
|
||||
end
|
||||
|
||||
local tMenuFuncs = {
|
||||
Save = function()
|
||||
if bReadOnly then
|
||||
sStatus = "Access denied"
|
||||
else
|
||||
local ok, err = save( sPath )
|
||||
if ok then
|
||||
sStatus="Saved to "..sPath
|
||||
else
|
||||
sStatus="Error saving to "..sPath
|
||||
end
|
||||
end
|
||||
redrawMenu()
|
||||
end,
|
||||
Print = function()
|
||||
local printer = peripheral.find( "printer" )
|
||||
if not printer then
|
||||
sStatus = "No printer attached"
|
||||
return
|
||||
end
|
||||
|
||||
local nPage = 0
|
||||
local sName = fs.getName( sPath )
|
||||
if printer.getInkLevel() < 1 then
|
||||
sStatus = "Printer out of ink"
|
||||
return
|
||||
elseif printer.getPaperLevel() < 1 then
|
||||
sStatus = "Printer out of paper"
|
||||
return
|
||||
end
|
||||
|
||||
local screenTerminal = term.current()
|
||||
local printerTerminal = {
|
||||
getCursorPos = printer.getCursorPos,
|
||||
setCursorPos = printer.setCursorPos,
|
||||
getSize = printer.getPageSize,
|
||||
write = printer.write,
|
||||
}
|
||||
printerTerminal.scroll = function()
|
||||
if nPage == 1 then
|
||||
printer.setPageTitle( sName.." (page "..nPage..")" )
|
||||
end
|
||||
|
||||
while not printer.newPage() do
|
||||
if printer.getInkLevel() < 1 then
|
||||
sStatus = "Printer out of ink, please refill"
|
||||
elseif printer.getPaperLevel() < 1 then
|
||||
sStatus = "Printer out of paper, please refill"
|
||||
else
|
||||
sStatus = "Printer output tray full, please empty"
|
||||
end
|
||||
|
||||
term.redirect( screenTerminal )
|
||||
redrawMenu()
|
||||
term.redirect( printerTerminal )
|
||||
|
||||
local timer = os.startTimer(0.5)
|
||||
sleep(0.5)
|
||||
end
|
||||
|
||||
nPage = nPage + 1
|
||||
if nPage == 1 then
|
||||
printer.setPageTitle( sName )
|
||||
else
|
||||
printer.setPageTitle( sName.." (page "..nPage..")" )
|
||||
end
|
||||
end
|
||||
|
||||
bMenu = false
|
||||
term.redirect( printerTerminal )
|
||||
local ok, error = pcall( function()
|
||||
term.scroll()
|
||||
for n, sLine in ipairs( tLines ) do
|
||||
print( sLine )
|
||||
end
|
||||
end )
|
||||
term.redirect( screenTerminal )
|
||||
if not ok then
|
||||
print( error )
|
||||
end
|
||||
|
||||
while not printer.endPage() do
|
||||
sStatus = "Printer output tray full, please empty"
|
||||
redrawMenu()
|
||||
sleep( 0.5 )
|
||||
end
|
||||
bMenu = true
|
||||
|
||||
if nPage > 1 then
|
||||
sStatus = "Printed "..nPage.." Pages"
|
||||
else
|
||||
sStatus = "Printed 1 Page"
|
||||
end
|
||||
redrawMenu()
|
||||
end,
|
||||
Exit = function()
|
||||
bRunning = false
|
||||
end,
|
||||
Run = function()
|
||||
local sTempPath = "/.temp"
|
||||
local ok, err = save( sTempPath )
|
||||
if ok then
|
||||
local nTask = shell.openTab( sTempPath )
|
||||
if nTask then
|
||||
shell.switchTab( nTask )
|
||||
else
|
||||
sStatus="Error starting Task"
|
||||
end
|
||||
fs.delete( sTempPath )
|
||||
else
|
||||
sStatus="Error saving to "..sTempPath
|
||||
end
|
||||
redrawMenu()
|
||||
end
|
||||
}
|
||||
|
||||
local function doMenuItem( _n )
|
||||
tMenuFuncs[tMenuItems[_n]]()
|
||||
if bMenu then
|
||||
bMenu = false
|
||||
term.setCursorBlink( true )
|
||||
end
|
||||
redrawMenu()
|
||||
end
|
||||
|
||||
local function setCursor( newX, newY )
|
||||
local oldX, oldY = x, y
|
||||
x, y = newX, newY
|
||||
local screenX = x - scrollX
|
||||
local screenY = y - scrollY
|
||||
|
||||
local bRedraw = false
|
||||
if screenX < 1 then
|
||||
scrollX = x - 1
|
||||
screenX = 1
|
||||
bRedraw = true
|
||||
elseif screenX > w then
|
||||
scrollX = x - w
|
||||
screenX = w
|
||||
bRedraw = true
|
||||
end
|
||||
|
||||
if screenY < 1 then
|
||||
scrollY = y - 1
|
||||
screenY = 1
|
||||
bRedraw = true
|
||||
elseif screenY > h-1 then
|
||||
scrollY = y - (h-1)
|
||||
screenY = h-1
|
||||
bRedraw = true
|
||||
end
|
||||
|
||||
recomplete()
|
||||
if bRedraw then
|
||||
redrawText()
|
||||
elseif y ~= oldY then
|
||||
redrawLine( oldY )
|
||||
redrawLine( y )
|
||||
else
|
||||
redrawLine( y )
|
||||
end
|
||||
term.setCursorPos( screenX, screenY )
|
||||
|
||||
redrawMenu()
|
||||
end
|
||||
|
||||
-- Actual program functionality begins
|
||||
load(sPath)
|
||||
|
||||
term.setBackgroundColour( bgColour )
|
||||
term.clear()
|
||||
term.setCursorPos(x,y)
|
||||
term.setCursorBlink( true )
|
||||
|
||||
recomplete()
|
||||
redrawText()
|
||||
redrawMenu()
|
||||
|
||||
local function acceptCompletion()
|
||||
if nCompletion then
|
||||
-- Find the common prefix of all the other suggestions which start with the same letter as the current one
|
||||
local sCompletion = tCompletions[ nCompletion ]
|
||||
local sFirstLetter = string.sub( sCompletion, 1, 1 )
|
||||
local sCommonPrefix = sCompletion
|
||||
for n=1,#tCompletions do
|
||||
local sResult = tCompletions[n]
|
||||
if n ~= nCompletion and string.find( sResult, sFirstLetter, 1, true ) == 1 then
|
||||
while #sCommonPrefix > 1 do
|
||||
if string.find( sResult, sCommonPrefix, 1, true ) == 1 then
|
||||
break
|
||||
else
|
||||
sCommonPrefix = string.sub( sCommonPrefix, 1, #sCommonPrefix - 1 )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Append this string
|
||||
tLines[y] = tLines[y] .. sCommonPrefix
|
||||
setCursor( x + string.len( sCommonPrefix ), y )
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle input
|
||||
while bRunning do
|
||||
local sEvent, param, param2, param3 = os.pullEvent()
|
||||
if sEvent == "key" then
|
||||
local oldX, oldY = x, y
|
||||
if param == keys.up then
|
||||
-- Up
|
||||
if not bMenu then
|
||||
if nCompletion then
|
||||
-- Cycle completions
|
||||
nCompletion = nCompletion - 1
|
||||
if nCompletion < 1 then
|
||||
nCompletion = #tCompletions
|
||||
end
|
||||
redrawLine(y)
|
||||
|
||||
elseif y > 1 then
|
||||
-- Move cursor up
|
||||
setCursor(
|
||||
math.min( x, string.len( tLines[y - 1] ) + 1 ),
|
||||
y - 1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys.down then
|
||||
-- Down
|
||||
if not bMenu then
|
||||
-- Move cursor down
|
||||
if nCompletion then
|
||||
-- Cycle completions
|
||||
nCompletion = nCompletion + 1
|
||||
if nCompletion > #tCompletions then
|
||||
nCompletion = 1
|
||||
end
|
||||
redrawLine(y)
|
||||
|
||||
elseif y < #tLines then
|
||||
-- Move cursor down
|
||||
setCursor(
|
||||
math.min( x, string.len( tLines[y + 1] ) + 1 ),
|
||||
y + 1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys.tab then
|
||||
-- Tab
|
||||
if not bMenu and not bReadOnly then
|
||||
if nCompletion and x == string.len(tLines[y]) + 1 then
|
||||
-- Accept autocomplete
|
||||
acceptCompletion()
|
||||
else
|
||||
-- Indent line
|
||||
local sLine = tLines[y]
|
||||
tLines[y] = string.sub(sLine,1,x-1) .. " " .. string.sub(sLine,x)
|
||||
setCursor( x + 2, y )
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys.pageUp then
|
||||
-- Page Up
|
||||
if not bMenu then
|
||||
-- Move up a page
|
||||
local newY
|
||||
if y - (h - 1) >= 1 then
|
||||
newY = y - (h - 1)
|
||||
else
|
||||
newY = 1
|
||||
end
|
||||
setCursor(
|
||||
math.min( x, string.len( tLines[newY] ) + 1 ),
|
||||
newY
|
||||
)
|
||||
end
|
||||
|
||||
elseif param == keys.pageDown then
|
||||
-- Page Down
|
||||
if not bMenu then
|
||||
-- Move down a page
|
||||
local newY
|
||||
if y + (h - 1) <= #tLines then
|
||||
newY = y + (h - 1)
|
||||
else
|
||||
newY = #tLines
|
||||
end
|
||||
local newX = math.min( x, string.len( tLines[newY] ) + 1 )
|
||||
setCursor( newX, newY )
|
||||
end
|
||||
|
||||
elseif param == keys.home then
|
||||
-- Home
|
||||
if not bMenu then
|
||||
-- Move cursor to the beginning
|
||||
if x > 1 then
|
||||
setCursor(1,y)
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys["end"] then
|
||||
-- End
|
||||
if not bMenu then
|
||||
-- Move cursor to the end
|
||||
local nLimit = string.len( tLines[y] ) + 1
|
||||
if x < nLimit then
|
||||
setCursor( nLimit, y )
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys.left then
|
||||
-- Left
|
||||
if not bMenu then
|
||||
if x > 1 then
|
||||
-- Move cursor left
|
||||
setCursor( x - 1, y )
|
||||
elseif x==1 and y>1 then
|
||||
setCursor( string.len( tLines[y-1] ) + 1, y - 1 )
|
||||
end
|
||||
else
|
||||
-- Move menu left
|
||||
nMenuItem = nMenuItem - 1
|
||||
if nMenuItem < 1 then
|
||||
nMenuItem = #tMenuItems
|
||||
end
|
||||
redrawMenu()
|
||||
end
|
||||
|
||||
elseif param == keys.right then
|
||||
-- Right
|
||||
if not bMenu then
|
||||
local nLimit = string.len( tLines[y] ) + 1
|
||||
if x < nLimit then
|
||||
-- Move cursor right
|
||||
setCursor( x + 1, y )
|
||||
elseif nCompletion and x == string.len(tLines[y]) + 1 then
|
||||
-- Accept autocomplete
|
||||
acceptCompletion()
|
||||
elseif x==nLimit and y<#tLines then
|
||||
-- Go to next line
|
||||
setCursor( 1, y + 1 )
|
||||
end
|
||||
else
|
||||
-- Move menu right
|
||||
nMenuItem = nMenuItem + 1
|
||||
if nMenuItem > #tMenuItems then
|
||||
nMenuItem = 1
|
||||
end
|
||||
redrawMenu()
|
||||
end
|
||||
|
||||
elseif param == keys.delete then
|
||||
-- Delete
|
||||
if not bMenu and not bReadOnly then
|
||||
local nLimit = string.len( tLines[y] ) + 1
|
||||
if x < nLimit then
|
||||
local sLine = tLines[y]
|
||||
tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
|
||||
recomplete()
|
||||
redrawLine(y)
|
||||
elseif y<#tLines then
|
||||
tLines[y] = tLines[y] .. tLines[y+1]
|
||||
table.remove( tLines, y+1 )
|
||||
recomplete()
|
||||
redrawText()
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys.backspace then
|
||||
-- Backspace
|
||||
if not bMenu and not bReadOnly then
|
||||
if x > 1 then
|
||||
-- Remove character
|
||||
local sLine = tLines[y]
|
||||
tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
|
||||
setCursor( x - 1, y )
|
||||
elseif y > 1 then
|
||||
-- Remove newline
|
||||
local sPrevLen = string.len( tLines[y-1] )
|
||||
tLines[y-1] = tLines[y-1] .. tLines[y]
|
||||
table.remove( tLines, y )
|
||||
setCursor( sPrevLen + 1, y - 1 )
|
||||
redrawText()
|
||||
end
|
||||
end
|
||||
|
||||
elseif param == keys.enter then
|
||||
-- Enter
|
||||
if not bMenu and not bReadOnly then
|
||||
-- Newline
|
||||
local sLine = tLines[y]
|
||||
local _,spaces=string.find(sLine,"^[ ]+")
|
||||
if not spaces then
|
||||
spaces=0
|
||||
end
|
||||
tLines[y] = string.sub(sLine,1,x-1)
|
||||
table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )
|
||||
setCursor( spaces + 1, y + 1 )
|
||||
redrawText()
|
||||
|
||||
elseif bMenu then
|
||||
-- Menu selection
|
||||
doMenuItem( nMenuItem )
|
||||
|
||||
end
|
||||
|
||||
elseif param == keys.leftCtrl or param == keys.rightCtrl or param == keys.rightAlt then
|
||||
-- Menu toggle
|
||||
bMenu = not bMenu
|
||||
if bMenu then
|
||||
term.setCursorBlink( false )
|
||||
else
|
||||
term.setCursorBlink( true )
|
||||
end
|
||||
redrawMenu()
|
||||
|
||||
end
|
||||
|
||||
elseif sEvent == "char" then
|
||||
if not bMenu and not bReadOnly then
|
||||
-- Input text
|
||||
local sLine = tLines[y]
|
||||
tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
|
||||
setCursor( x + 1, y )
|
||||
|
||||
elseif bMenu then
|
||||
-- Select menu items
|
||||
for n,sMenuItem in ipairs( tMenuItems ) do
|
||||
if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
|
||||
doMenuItem( n )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif sEvent == "paste" then
|
||||
if not bMenu and not bReadOnly then
|
||||
-- Input text
|
||||
local sLine = tLines[y]
|
||||
tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
|
||||
setCursor( x + string.len( param ), y )
|
||||
end
|
||||
|
||||
elseif sEvent == "mouse_click" then
|
||||
if not bMenu then
|
||||
if param == 1 then
|
||||
-- Left click
|
||||
local cx,cy = param2, param3
|
||||
if cy < h then
|
||||
local newY = math.min( math.max( scrollY + cy, 1 ), #tLines )
|
||||
local newX = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[newY] ) + 1 )
|
||||
setCursor( newX, newY )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif sEvent == "mouse_scroll" then
|
||||
if not bMenu then
|
||||
if param == -1 then
|
||||
-- Scroll up
|
||||
if scrollY > 0 then
|
||||
-- Move cursor up
|
||||
scrollY = scrollY - 1
|
||||
redrawText()
|
||||
end
|
||||
|
||||
elseif param == 1 then
|
||||
-- Scroll down
|
||||
local nMaxScroll = #tLines - (h-1)
|
||||
if scrollY < nMaxScroll then
|
||||
-- Move cursor down
|
||||
scrollY = scrollY + 1
|
||||
redrawText()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
elseif sEvent == "term_resize" then
|
||||
w,h = term.getSize()
|
||||
setCursor( x, y )
|
||||
redrawMenu()
|
||||
redrawText()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Cleanup
|
||||
term.clear()
|
||||
term.setCursorBlink( false )
|
||||
term.setCursorPos( 1, 1 )
|
4
bin/netutil1
Normal file
4
bin/netutil1
Normal file
|
@ -0,0 +1,4 @@
|
|||
-- testing
|
||||
net.openModems()
|
||||
net.setWorkstationStatus(true)
|
||||
print(tostring(net.getWorkstationStatus()))
|
50
bin/nmap
Normal file
50
bin/nmap
Normal file
|
@ -0,0 +1,50 @@
|
|||
--Initializing IP address generator
|
||||
|
||||
local tArgs = {...}
|
||||
if #tArgs < 4 then
|
||||
kerneldraw.printAppInfo("nmap", "No IP address specified")
|
||||
else
|
||||
kerneldraw.printAppSuccess("nmap", "Scanning for specified IP")
|
||||
end
|
||||
|
||||
if #tArgs == 5 then
|
||||
kerneldraw.printAppSuccess("nmap", "Specified DNS record")
|
||||
end
|
||||
|
||||
local ip, node
|
||||
|
||||
if #tArgs < 4 then
|
||||
local x = tostring(math.random(0, 255))
|
||||
local y = tostring(math.random(0, 255))
|
||||
local z = tostring(math.random(0, 255))
|
||||
local r = tostring(math.random(0, 255))
|
||||
ip = x.."."..y.."."..z.."."..r
|
||||
elseif #tArgs >= 4 then
|
||||
ip = tArgs[1].."."..tArgs[2].."."..tArgs[3].."."..tArgs[4]
|
||||
end
|
||||
|
||||
if not fs.exists("/network") or not fs.isDir("/network") then
|
||||
fs.makeDir("/network")
|
||||
end
|
||||
|
||||
--node = "/network/"..ip
|
||||
|
||||
kerneldraw.printAppInfo("nmap", "Found "..ip)
|
||||
|
||||
if #tArgs == 5 then
|
||||
kerneldraw.printAppSuccess("nmap", "Assigned DNS record "..tArgs[5])
|
||||
node = "/network/"..tArgs[5]
|
||||
else
|
||||
kerneldraw.printAppWarning("nmap", "No DNS record found, defaulting to IP")
|
||||
node = "/network/"..ip
|
||||
end
|
||||
|
||||
if fs.exists(node) and fs.isDir(node) then
|
||||
kerneldraw.printAppInfo("nmap", ip.." already known")
|
||||
else
|
||||
fs.makeDir(node)
|
||||
fs.makeDir(node.."/sys")
|
||||
fs.makeDir(node.."/home")
|
||||
fs.makeDir(node.."/bin")
|
||||
kerneldraw.printAppSuccess("nmap", ip.." added to network")
|
||||
end
|
50
bin/passwd
Normal file
50
bin/passwd
Normal file
|
@ -0,0 +1,50 @@
|
|||
local tArgs = {...}
|
||||
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo("passwd", "Specify a user")
|
||||
return
|
||||
end
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if fs.exists("/etc/passwd/"..tArgs[1]..".dat") and not fs.isDir("/etc/passwd/"..tArgs[1]..".dat") then
|
||||
local passwd = nil
|
||||
local passwd_reenter = nil
|
||||
passwd = kernel.secureInputReturn("New Password: ")
|
||||
os.pullEvent = function()
|
||||
local eventData = { os.pullEventRaw( _sFilter ) }
|
||||
if eventData[1] == "terminate" then
|
||||
error( "Terminated", 0 )
|
||||
end
|
||||
return unpack( eventData )
|
||||
end
|
||||
if passwd == "" or passwd == nil then
|
||||
kerneldraw.printAppInfo("passwd","Invalid password")
|
||||
return
|
||||
else
|
||||
passwd_reenter = kernel.secureInput("Reenter: ", passwd)
|
||||
os.pullEvent = function()
|
||||
local eventData = { os.pullEventRaw( _sFilter ) }
|
||||
if eventData[1] == "terminate" then
|
||||
error( "Terminated", 0 )
|
||||
end
|
||||
return unpack( eventData )
|
||||
end
|
||||
if not passwd == passwd_reenter then
|
||||
kerneldraw.printAppInfo("passwd","Passwords don't match")
|
||||
return
|
||||
end
|
||||
end
|
||||
if security.passbyte(tArgs[1], passwd) then
|
||||
kerneldraw.printAppSuccess("passwd", "Password of user "..tArgs[1].." changed")
|
||||
log.writeSecurity("Password of user "..tArgs[1].." changed")
|
||||
else
|
||||
kerneldraw.printAppInfo("passwd", "Failed to change password")
|
||||
log.writeSecurity("Failed to change password")
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("security", "User " .. tArgs[1] .. " does not exist")
|
||||
end
|
160
bin/pastebin
Normal file
160
bin/pastebin
Normal file
|
@ -0,0 +1,160 @@
|
|||
local function printUsage()
|
||||
local programName = "pastebin"
|
||||
print("Usages:")
|
||||
print(programName .. " put <filename>")
|
||||
print(programName .. " get <code> <filename>")
|
||||
print(programName .. " run <code> <arguments>")
|
||||
end
|
||||
|
||||
local tArgs = { ... }
|
||||
if #tArgs < 2 then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
if not http then
|
||||
printError("Pastebin requires the http API")
|
||||
printError("Set http.enabled to true in CC: Tweaked's config")
|
||||
return
|
||||
end
|
||||
|
||||
--- Attempts to guess the pastebin ID from the given code or URL
|
||||
local function extractId(paste)
|
||||
local patterns = {
|
||||
"^([%a%d]+)$",
|
||||
"^https?://pastebin.com/([%a%d]+)$",
|
||||
"^pastebin.com/([%a%d]+)$",
|
||||
"^https?://pastebin.com/raw/([%a%d]+)$",
|
||||
"^pastebin.com/raw/([%a%d]+)$",
|
||||
}
|
||||
|
||||
for i = 1, #patterns do
|
||||
local code = paste:match(patterns[i])
|
||||
if code then return code end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get(url)
|
||||
local paste = extractId(url)
|
||||
if not paste then
|
||||
io.stderr:write("Invalid pastebin code.\n")
|
||||
io.write("The code is the ID at the end of the pastebin.com URL.\n")
|
||||
return
|
||||
end
|
||||
|
||||
write("Connecting to pastebin.com... ")
|
||||
-- Add a cache buster so that spam protection is re-checked
|
||||
local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30))
|
||||
local response, err = http.get(
|
||||
"https://pastebin.com/raw/" .. textutils.urlEncode(paste) .. "?cb=" .. cacheBuster
|
||||
)
|
||||
|
||||
if response then
|
||||
-- If spam protection is activated, we get redirected to /paste with Content-Type: text/html
|
||||
local headers = response.getResponseHeaders()
|
||||
if not headers["Content-Type"] or not headers["Content-Type"]:find("^text/plain") then
|
||||
io.stderr:write("Failed.\n")
|
||||
print("Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode(paste))
|
||||
return
|
||||
end
|
||||
|
||||
print("Success.")
|
||||
|
||||
local sResponse = response.readAll()
|
||||
response.close()
|
||||
return sResponse
|
||||
else
|
||||
io.stderr:write("Failed.\n")
|
||||
print(err)
|
||||
end
|
||||
end
|
||||
|
||||
local sCommand = tArgs[1]
|
||||
if sCommand == "put" then
|
||||
-- Upload a file to pastebin.com
|
||||
-- Determine file to upload
|
||||
local sFile = tArgs[2]
|
||||
local sPath = shell.resolve(sFile)
|
||||
if not fs.exists(sPath) or fs.isDir(sPath) then
|
||||
print("No such file")
|
||||
return
|
||||
end
|
||||
|
||||
-- Read in the file
|
||||
local sName = fs.getName(sPath)
|
||||
local file = fs.open(sPath, "r")
|
||||
local sText = file.readAll()
|
||||
file.close()
|
||||
|
||||
-- POST the contents to pastebin
|
||||
write("Connecting to pastebin.com... ")
|
||||
local key = "0ec2eb25b6166c0c27a394ae118ad829"
|
||||
local response = http.post(
|
||||
"https://pastebin.com/api/api_post.php",
|
||||
"api_option=paste&" ..
|
||||
"api_dev_key=" .. key .. "&" ..
|
||||
"api_paste_format=lua&" ..
|
||||
"api_paste_name=" .. textutils.urlEncode(sName) .. "&" ..
|
||||
"api_paste_code=" .. textutils.urlEncode(sText)
|
||||
)
|
||||
|
||||
if response then
|
||||
print("Success.")
|
||||
|
||||
local sResponse = response.readAll()
|
||||
response.close()
|
||||
|
||||
local sCode = string.match(sResponse, "[^/]+$")
|
||||
print("Uploaded as " .. sResponse)
|
||||
print("Run \"pastebin get " .. sCode .. "\" to download anywhere")
|
||||
|
||||
else
|
||||
print("Failed.")
|
||||
end
|
||||
|
||||
elseif sCommand == "get" then
|
||||
-- Download a file from pastebin.com
|
||||
if #tArgs < 3 then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
-- Determine file to download
|
||||
local sCode = tArgs[2]
|
||||
local sFile = tArgs[3]
|
||||
local sPath = shell.resolve(sFile)
|
||||
if fs.exists(sPath) then
|
||||
print("File already exists")
|
||||
return
|
||||
end
|
||||
|
||||
-- GET the contents from pastebin
|
||||
local res = get(sCode)
|
||||
if res then
|
||||
local file = fs.open(sPath, "w")
|
||||
file.write(res)
|
||||
file.close()
|
||||
|
||||
print("Downloaded as " .. sFile)
|
||||
end
|
||||
elseif sCommand == "run" then
|
||||
local sCode = tArgs[2]
|
||||
|
||||
local res = get(sCode)
|
||||
if res then
|
||||
local func, err = load(res, sCode, "t", _ENV)
|
||||
if not func then
|
||||
printError(err)
|
||||
return
|
||||
end
|
||||
local success, msg = pcall(func, select(3, ...))
|
||||
if not success then
|
||||
printError(msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
printUsage()
|
||||
return
|
||||
end
|
10
bin/peripherals
Normal file
10
bin/peripherals
Normal file
|
@ -0,0 +1,10 @@
|
|||
local tPeripherals = peripheral.getNames()
|
||||
print("Attached Peripherals:")
|
||||
if #tPeripherals > 0 then
|
||||
for n = 1, #tPeripherals do
|
||||
local sPeripheral = tPeripherals[n]
|
||||
print(sPeripheral .. " (" .. table.concat({ peripheral.getType(sPeripheral) }, ", ") .. ")")
|
||||
end
|
||||
else
|
||||
print("None")
|
||||
end
|
118
bin/redstone
Normal file
118
bin/redstone
Normal file
|
@ -0,0 +1,118 @@
|
|||
local tArgs = { ... }
|
||||
|
||||
local function printUsage()
|
||||
local programName = "redstone"
|
||||
print("Usages:")
|
||||
print(programName .. " probe")
|
||||
print(programName .. " set <side> <value>")
|
||||
print(programName .. " set <side> <color> <value>")
|
||||
print(programName .. " pulse <side> <count> <period>")
|
||||
end
|
||||
|
||||
local sCommand = tArgs[1]
|
||||
if sCommand == "probe" then
|
||||
-- "redstone probe"
|
||||
-- Regular input
|
||||
print("Redstone inputs: ")
|
||||
|
||||
local count = 0
|
||||
local bundledCount = 0
|
||||
for _, sSide in ipairs(redstone.getSides()) do
|
||||
if redstone.getBundledInput(sSide) > 0 then
|
||||
bundledCount = bundledCount + 1
|
||||
end
|
||||
if redstone.getInput(sSide) then
|
||||
if count > 0 then
|
||||
io.write(", ")
|
||||
end
|
||||
io.write(sSide)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if count > 0 then
|
||||
print(".")
|
||||
else
|
||||
print("None.")
|
||||
end
|
||||
|
||||
-- Bundled input
|
||||
if bundledCount > 0 then
|
||||
print()
|
||||
print("Bundled inputs:")
|
||||
for _, sSide in ipairs(redstone.getSides()) do
|
||||
local nInput = redstone.getBundledInput(sSide)
|
||||
if nInput ~= 0 then
|
||||
write(sSide .. ": ")
|
||||
local count = 0
|
||||
for sColour, nColour in pairs(colors) do
|
||||
if type(nColour) == "number" and colors.test(nInput, nColour) then
|
||||
if count > 0 then
|
||||
write(", ")
|
||||
end
|
||||
if term.isColour() then
|
||||
term.setTextColour(nColour)
|
||||
end
|
||||
write(sColour)
|
||||
if term.isColour() then
|
||||
term.setTextColour(colours.white)
|
||||
end
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
print(".")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif sCommand == "pulse" then
|
||||
-- "redstone pulse"
|
||||
local sSide = tArgs[2]
|
||||
local nCount = tonumber(tArgs[3]) or 1
|
||||
local nPeriod = tonumber(tArgs[4]) or 0.5
|
||||
for _ = 1, nCount do
|
||||
redstone.setOutput(sSide, true)
|
||||
sleep(nPeriod / 2)
|
||||
redstone.setOutput(sSide, false)
|
||||
sleep(nPeriod / 2)
|
||||
end
|
||||
|
||||
elseif sCommand == "set" then
|
||||
-- "redstone set"
|
||||
local sSide = tArgs[2]
|
||||
if #tArgs > 3 then
|
||||
-- Bundled cable output
|
||||
local sColour = tArgs[3]
|
||||
local nColour = colors[sColour] or colours[sColour]
|
||||
if type(nColour) ~= "number" then
|
||||
printError("No such color")
|
||||
return
|
||||
end
|
||||
|
||||
local sValue = tArgs[4]
|
||||
if sValue == "true" then
|
||||
rs.setBundledOutput(sSide, colors.combine(rs.getBundledOutput(sSide), nColour))
|
||||
elseif sValue == "false" then
|
||||
rs.setBundledOutput(sSide, colors.subtract(rs.getBundledOutput(sSide), nColour))
|
||||
else
|
||||
print("Value must be boolean")
|
||||
end
|
||||
else
|
||||
-- Regular output
|
||||
local sValue = tArgs[3]
|
||||
local nValue = tonumber(sValue)
|
||||
if sValue == "true" then
|
||||
rs.setOutput(sSide, true)
|
||||
elseif sValue == "false" then
|
||||
rs.setOutput(sSide, false)
|
||||
elseif nValue and nValue >= 0 and nValue <= 15 then
|
||||
rs.setAnalogOutput(sSide, nValue)
|
||||
else
|
||||
print("Value must be boolean or 0-15")
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
-- Something else
|
||||
printUsage()
|
||||
|
||||
end
|
30
bin/rm
Normal file
30
bin/rm
Normal file
|
@ -0,0 +1,30 @@
|
|||
local args = table.pack(...)
|
||||
|
||||
if args.n < 1 then
|
||||
local programName = "rm"
|
||||
print("Usage: " .. programName .. " <paths>")
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, args.n do
|
||||
local files = fs.find(shell.resolve(args[i]))
|
||||
if #files > 0 then
|
||||
for _, file in ipairs(files) do
|
||||
if fs.isReadOnly(file) then
|
||||
printError("Cannot delete read-only file /" .. file)
|
||||
elseif fs.isDriveRoot(file) then
|
||||
printError("Cannot delete mount /" .. file)
|
||||
if fs.isDir(file) then
|
||||
print("To delete its contents run rm /" .. fs.combine(file, "*"))
|
||||
end
|
||||
else
|
||||
local ok, err = pcall(fs.delete, file)
|
||||
if not ok then
|
||||
printError((err:gsub("^pcall: ", "")))
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
printError(args[i] .. ": No matching files")
|
||||
end
|
||||
end
|
375
bin/screenfetch
Normal file
375
bin/screenfetch
Normal file
|
@ -0,0 +1,375 @@
|
|||
if os.pullEvent ~= nil then
|
||||
|
||||
local ccart, ccart_fg, ccart_bg, ccart_adv_fg, ccart_adv_bg, ccart_width
|
||||
|
||||
if ... == "--small" then
|
||||
|
||||
ccart = ([[\159\143\143\143\143\143\143\143\144
|
||||
\150\136\144 \150
|
||||
\150\130 \131 \150
|
||||
\150 \150
|
||||
\150 \150
|
||||
\150 \140\150
|
||||
]]):gsub("\\130", "\130"):gsub("\\131", "\131"):gsub("\\136", "\136"):gsub("\\140", "\140"):gsub("\\143", "\143"):gsub("\\144", "\144"):gsub("\\150", "\149"):gsub("\\159", "\159")
|
||||
|
||||
ccart_fg = [[ffffffff7
|
||||
f00fffff7
|
||||
f0f0ffff7
|
||||
ffffffff8
|
||||
ffffffff8
|
||||
f888888f8
|
||||
fffffffff]]
|
||||
|
||||
ccart_bg = [[77777777f
|
||||
7ffffffff
|
||||
7ffffffff
|
||||
8ffffffff
|
||||
8ffffffff
|
||||
88888888f
|
||||
fffffffff]]
|
||||
|
||||
ccart_adv_fg = [[ffffffff4
|
||||
f00fffff4
|
||||
f0f0ffff4
|
||||
ffffffff4
|
||||
ffffffff4
|
||||
f444444d4
|
||||
fffffffff]]
|
||||
|
||||
ccart_adv_bg = [[44444444f
|
||||
4ffffffff
|
||||
4ffffffff
|
||||
4ffffffff
|
||||
4ffffffff
|
||||
44444444f
|
||||
fffffffff]]
|
||||
|
||||
ccart_width = 10
|
||||
|
||||
else
|
||||
ccart = [[------------------------
|
||||
| |
|
||||
| -------------------- |
|
||||
| | \ | |
|
||||
| | / __ | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| -------------------- |
|
||||
| |
|
||||
| [=] |
|
||||
| |
|
||||
------------------------]]
|
||||
|
||||
ccart_fg = [[ffffffffffffffffffffffff
|
||||
f7777777777777777777777f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ff0fffffffffffffffff7f
|
||||
f7ff0f00ffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8888888888888888888888f
|
||||
f888888888888888888fff8f
|
||||
f8888888888888888888888f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
ccart_bg = [[ffffffffffffffffffffffff
|
||||
f7777777777777777777777f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f7ffffffffffffffffffff7f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8ffffffffffffffffffff8f
|
||||
f8888888888888888888888f
|
||||
f888888888888888888fff8f
|
||||
f8888888888888888888888f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
ccart_adv_fg = [[ffffffffffffffffffffffff
|
||||
f4444444444444444444444f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ff0fffffffffffffffff4f
|
||||
f4ff0f00ffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4444444444444444444444f
|
||||
f444444444444444444ddd4f
|
||||
f4444444444444444444444f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
ccart_adv_bg = [[ffffffffffffffffffffffff
|
||||
f4444444444444444444444f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4444444444444444444444f
|
||||
f444444444444444444ddd4f
|
||||
f4444444444444444444444f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
ccart_width = 25
|
||||
|
||||
end
|
||||
|
||||
local function fg(l) if term.isColor() then return string.rep("4", l) else return string.rep("8", l) end end
|
||||
local function text(title, str) return {title .. str, fg(string.len(title)) .. string.rep("0", string.len(str)), string.rep("f", string.len(title .. str))} end
|
||||
|
||||
local function time(n)
|
||||
local h = math.floor(n / 3600)
|
||||
local m = math.floor(n / 60) % 60
|
||||
local s = n % 60
|
||||
local retval = s .. "s"
|
||||
if m > 0 or h > 0 then retval = m .. "m " .. retval end
|
||||
if h > 0 then retval = h .. "h " .. retval end
|
||||
return retval
|
||||
end
|
||||
|
||||
local function ext(retval)
|
||||
if debug ~= nil then table.insert(retval, text(" ", "Debug enabled")) end
|
||||
if http ~= nil then table.insert(retval, text(" ", "HTTP enabled"))
|
||||
if http.websocket ~= nil then table.insert(retval, text(" ", "CC: Tweaked")) end end
|
||||
if mounter ~= nil then table.insert(retval, text(" ", "CraftOS-PC")) end
|
||||
if term.setGraphicsMode ~= nil then table.insert(retval, text(" ", "CraftOS-PC GFX")) end
|
||||
if term.screenshot ~= nil then table.insert(retval, text(" ", "CraftOS-PC 2")) end
|
||||
if ccemux ~= nil then table.insert(retval, text(" ", "CCEmuX")) end
|
||||
if fs.exists(".mbs") or fs.exists("rom/.mbs") then table.insert(retval, text(" ", "MBS")) end
|
||||
if type(kernel) == "table" then table.insert(retval, text(" ", "CCKernel2")) end
|
||||
return retval
|
||||
end
|
||||
|
||||
local function getRuntime()
|
||||
if os.about ~= nil then return string.sub(os.about(), 1, string.find(os.about(), "\n"))
|
||||
elseif ccemux ~= nil then return ccemux.getVersion()
|
||||
elseif _MC_VERSION ~= nil then return _MC_VERSION
|
||||
else return "Unknown" end
|
||||
end
|
||||
|
||||
local sysinfo = {
|
||||
text(os.getComputerLabel() or "Untitled Computer", ""),
|
||||
text("Type: ", commands ~= nil and "Command Computer" or term.isColor() and "Advanced Computer" or "Standard Computer"),
|
||||
text("OS: ", kernel.getOS()),
|
||||
text("Kernel: ", kernel.getRelease()),
|
||||
text("Runtime: ", getRuntime()),
|
||||
text("Lua: ", _VERSION),
|
||||
text("Host: ", _HOST),
|
||||
text("Uptime: ", time(os.clock())),
|
||||
text("Extensions: ", "")
|
||||
}
|
||||
ext(sysinfo)
|
||||
local lines, sw, sh = 2, term.getSize()
|
||||
term.clear()
|
||||
term.setCursorPos(1, 2)
|
||||
for i = 1, string.len(ccart), ccart_width do
|
||||
term.blit(string.sub(ccart, i, i+ccart_width-2), string.sub(term.isColor() and ccart_adv_fg or ccart_fg, i, i+ccart_width-2), string.sub(term.isColor() and ccart_adv_bg or ccart_bg, i, i+ccart_width-2))
|
||||
write(" ")
|
||||
if sysinfo[((i-1)/ccart_width)+1] ~= nil then term.blit(table.unpack(sysinfo[((i-1)/ccart_width)+1])) end
|
||||
print("")
|
||||
lines = lines + 1
|
||||
end
|
||||
for i = lines - 1, #sysinfo do
|
||||
write(string.rep(" ", ccart_width + 1))
|
||||
term.blit(table.unpack(sysinfo[i]))
|
||||
print("")
|
||||
end
|
||||
print("")
|
||||
if term.screenshot ~= nil then term.screenshot() end
|
||||
sleep(0.25)
|
||||
|
||||
elseif require("filesystem") ~= nil then
|
||||
|
||||
-- TODO: Find better art
|
||||
local ccart = [[------------------------
|
||||
| |
|
||||
| -------------------- |
|
||||
| | \ | |
|
||||
| | / __ | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| -------------------- |
|
||||
| |
|
||||
| [=] |
|
||||
| |
|
||||
------------------------]]
|
||||
|
||||
local ccart_fg = [[ffffffffffffffffffffffff
|
||||
f0000000000000000000000f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ff0fffffffffffffffff0f
|
||||
f0ff0f00ffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0000000000000000000000f
|
||||
f000000000000000000fff0f
|
||||
f0000000000000000000000f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
local ccart_bg = [[ffffffffffffffffffffffff
|
||||
f0000000000000000000000f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0ffffffffffffffffffff0f
|
||||
f0000000000000000000000f
|
||||
f000000000000000000fff0f
|
||||
f0000000000000000000000f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
local ccart_adv_fg = [[ffffffffffffffffffffffff
|
||||
f4444444444444444444444f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ff0fffffffffffffffff4f
|
||||
f4ff0f00ffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4444444444444444444444f
|
||||
f444444444444444444ddd4f
|
||||
f4444444444444444444444f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
local ccart_adv_bg = [[ffffffffffffffffffffffff
|
||||
f4444444444444444444444f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4ffffffffffffffffffff4f
|
||||
f4444444444444444444444f
|
||||
f444444444444444444ddd4f
|
||||
f4444444444444444444444f
|
||||
ffffffffffffffffffffffff]]
|
||||
|
||||
local component = require("component")
|
||||
local computer = require("computer")
|
||||
local term = require("term")
|
||||
local gpu = term.gpu()
|
||||
|
||||
local function fg(l) if gpu.getDepth() > 1 then return string.rep("4", l) else return string.rep("0", l) end end
|
||||
local function text(title, str) return {title .. str, fg(string.len(title)) .. string.rep("0", string.len(str)), string.rep("f", string.len(title .. str))} end
|
||||
|
||||
local function time(n)
|
||||
local h = math.floor(n / 3600)
|
||||
local m = math.floor(n / 60) % 60
|
||||
local s = n % 60
|
||||
local retval = s .. "s"
|
||||
if m > 0 or h > 0 then retval = m .. "m " .. retval end
|
||||
if h > 0 then retval = h .. "h " .. retval end
|
||||
return retval
|
||||
end
|
||||
|
||||
local function mem(bytes)
|
||||
if bytes > 1048576 then return string.gsub(string.sub((math.floor((bytes / 1048576) * 1000) / 1000) .. "", 1, 4), "%.$", "") .. " MB"
|
||||
elseif bytes > 1024 then return string.gsub(string.sub((math.floor((bytes / 1024) * 1000) / 1000) .. "", 1, 4), "%.$", "") .. " kB"
|
||||
else return bytes .. " B" end
|
||||
end
|
||||
|
||||
local function ext(retval)
|
||||
for address, type in component.list() do table.insert(retval, text(" " .. type .. " ", address)) end
|
||||
return retval
|
||||
end
|
||||
|
||||
local tier = "Unknown"
|
||||
for k,v in pairs(component.computer.getDeviceInfo()) do if v.class == "processor" then tier = string.match(v.product, "FlexiArch (%d+) Processor") end end
|
||||
|
||||
local sysinfo = {
|
||||
text("OpenComputers", ""),
|
||||
text("Tier: ", tier),
|
||||
text("OS: ", _OSVERSION),
|
||||
text("Lua: ", _VERSION),
|
||||
text("RAM: ", mem(computer.totalMemory() - computer.freeMemory()) .. " / " .. mem(computer.totalMemory())),
|
||||
text("Uptime: ", time(computer.uptime())),
|
||||
text("Components: ", "")
|
||||
}
|
||||
ext(sysinfo)
|
||||
|
||||
local ccColors = {
|
||||
["0"] = 0xFFFFFF,
|
||||
["4"] = 0xFFFF00,
|
||||
["7"] = 0x404040,
|
||||
["8"] = 0x7F7F7F,
|
||||
d = 0x00FF00,
|
||||
f = 0x000000
|
||||
}
|
||||
|
||||
local function blit(text, fg, bg)
|
||||
if text == "" then return end
|
||||
if #text ~= #fg or #fg ~= #bg then error("Unbalanced string lengths in blit", 2) end
|
||||
if #text > term.getViewport() - term.getCursor() then
|
||||
text = string.sub(text, 1, term.getViewport() - term.getCursor(), nil)
|
||||
fg = string.sub(fg, 1, term.getViewport() - term.getCursor(), nil)
|
||||
bg = string.sub(bg, 1, term.getViewport() - term.getCursor(), nil)
|
||||
end
|
||||
for i = 1, #text do
|
||||
if ccColors[string.sub(fg, i, i)] == nil then error("Unknown color " .. string.sub(fg, i, i)) end
|
||||
if ccColors[string.sub(bg, i, i)] == nil then error("Unknown color " .. string.sub(bg, i, i)) end
|
||||
gpu.setForeground(ccColors[string.sub(fg, i, i)])
|
||||
gpu.setBackground(ccColors[string.sub(bg, i, i)])
|
||||
term.write(string.sub(text, i, i))
|
||||
end
|
||||
end
|
||||
|
||||
print("")
|
||||
for i = 1, string.len(ccart), 25 do
|
||||
blit(string.sub(ccart, i, i+23), string.sub(gpu.getDepth() > 1 and ccart_adv_fg or ccart_fg, i, i+23), string.sub(gpu.getDepth() > 1 and ccart_adv_bg or ccart_bg, i, i+23))
|
||||
term.write(" ")
|
||||
if sysinfo[((i-1)/25)+1] ~= nil then blit(table.unpack(sysinfo[((i-1)/25)+1])) end
|
||||
print("")
|
||||
end
|
||||
if #sysinfo > 16 then for i = 16, #sysinfo do
|
||||
term.write(string.rep(" ", 26))
|
||||
blit(table.unpack(sysinfo[i]))
|
||||
print("")
|
||||
end end
|
||||
print("")
|
||||
os.sleep(0.25)
|
||||
|
||||
else print("Unknown computer type") end
|
7
bin/script
Normal file
7
bin/script
Normal file
|
@ -0,0 +1,7 @@
|
|||
local tArgs = {...}
|
||||
|
||||
if #tArgs >= 1 then
|
||||
shell.executeScript(shell.resolve(tArgs[1]))
|
||||
else
|
||||
kerneldraw.printAppInfo("script", "No file specified")
|
||||
end
|
55
bin/set
Normal file
55
bin/set
Normal file
|
@ -0,0 +1,55 @@
|
|||
local pp = require "cc.pretty"
|
||||
|
||||
local tArgs = { ... }
|
||||
if #tArgs == 0 then
|
||||
-- "set"
|
||||
local _, y = term.getCursorPos()
|
||||
local tSettings = {}
|
||||
for n, sName in ipairs(settings.getNames()) do
|
||||
tSettings[n] = textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName))
|
||||
end
|
||||
textutils.pagedPrint(table.concat(tSettings, "\n"), y - 3)
|
||||
|
||||
elseif #tArgs == 1 then
|
||||
-- "set foo"
|
||||
local sName = tArgs[1]
|
||||
local deets = settings.getDetails(sName)
|
||||
local msg = pp.text(sName, colors.cyan) .. " is " .. pp.pretty(deets.value)
|
||||
if deets.default ~= nil and deets.value ~= deets.default then
|
||||
msg = msg .. " (default is " .. pp.pretty(deets.default) .. ")"
|
||||
end
|
||||
pp.print(msg)
|
||||
if deets.description then print(deets.description) end
|
||||
|
||||
else
|
||||
-- "set foo bar"
|
||||
local sName = tArgs[1]
|
||||
local sValue = tArgs[2]
|
||||
local value
|
||||
if sValue == "true" then
|
||||
value = true
|
||||
elseif sValue == "false" then
|
||||
value = false
|
||||
elseif sValue == "nil" then
|
||||
value = nil
|
||||
elseif tonumber(sValue) then
|
||||
value = tonumber(sValue)
|
||||
else
|
||||
value = sValue
|
||||
end
|
||||
|
||||
local option = settings.getDetails(sName)
|
||||
if value == nil then
|
||||
settings.unset(sName)
|
||||
print(textutils.serialize(sName) .. " unset")
|
||||
elseif option.type and option.type ~= type(value) then
|
||||
printError(("%s is not a valid %s."):format(textutils.serialize(sValue), option.type))
|
||||
else
|
||||
settings.set(sName, value)
|
||||
print(textutils.serialize(sName) .. " set to " .. textutils.serialize(value))
|
||||
end
|
||||
|
||||
if value ~= option.value then
|
||||
settings.save()
|
||||
end
|
||||
end
|
256
bin/sh
Normal file
256
bin/sh
Normal file
|
@ -0,0 +1,256 @@
|
|||
local tArgs = {...}
|
||||
|
||||
local parentShell = shell
|
||||
|
||||
local bExit = false
|
||||
local sDir = (parentShell and parentShell.dir()) or ""
|
||||
local sPath = (parentShell and parentShell.path()) or ".:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
|
||||
local tAliases = (parentShell and parentShell.aliases()) or {}
|
||||
local tProgramStack = {}
|
||||
|
||||
local shell = {}
|
||||
local tEnv = {
|
||||
["shell"] = shell,
|
||||
}
|
||||
|
||||
local function findArg(arg)
|
||||
for _,v in ipairs(tArgs) do
|
||||
if v == arg then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Colours
|
||||
local promptColour, textColour, bgColour
|
||||
if term.isColour() then
|
||||
promptColour = colours.yellow
|
||||
textColour = colours.white
|
||||
bgColour = colours.black
|
||||
else
|
||||
promptColour = colours.white
|
||||
textColour = colours.white
|
||||
bgColour = colours.black
|
||||
end
|
||||
|
||||
|
||||
local function run( _sCommand, ... )
|
||||
local sPath = shell.resolveProgram( _sCommand )
|
||||
if sPath ~= nil then
|
||||
tProgramStack[#tProgramStack + 1] = sPath
|
||||
local result = os.run( tEnv, sPath, ... )
|
||||
tProgramStack[#tProgramStack] = nil
|
||||
return result
|
||||
else
|
||||
printError( "No such program" )
|
||||
printError( _sCommand .. ": Command not found" )
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function runLine( _sLine )
|
||||
local tWords = {}
|
||||
for match in string.gmatch( _sLine, "[^ \t]+" ) do
|
||||
table.insert( tWords, match )
|
||||
end
|
||||
|
||||
local sCommand = tWords[1]
|
||||
if sCommand then
|
||||
return run( sCommand, unpack( tWords, 2 ) )
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Install shell API
|
||||
function shell.run( ... )
|
||||
return runLine( table.concat( { ... }, " " ) )
|
||||
end
|
||||
|
||||
function shell.exit()
|
||||
bExit = true
|
||||
end
|
||||
|
||||
function shell.dir()
|
||||
return sDir
|
||||
end
|
||||
|
||||
function shell.setDir( _sDir )
|
||||
sDir = _sDir
|
||||
end
|
||||
|
||||
function shell.path()
|
||||
return sPath
|
||||
end
|
||||
|
||||
function shell.setPath( _sPath )
|
||||
sPath = _sPath
|
||||
end
|
||||
|
||||
function shell.resolve( _sPath )
|
||||
local sStartChar = string.sub( _sPath, 1, 1 )
|
||||
if sStartChar == "/" or sStartChar == "\\" then
|
||||
return fs.combine( "", _sPath )
|
||||
else
|
||||
return fs.combine( sDir, _sPath )
|
||||
end
|
||||
end
|
||||
|
||||
function shell.resolveProgram( _sCommand )
|
||||
-- Substitute aliases firsts
|
||||
if tAliases[ _sCommand ] ~= nil then
|
||||
_sCommand = tAliases[ _sCommand ]
|
||||
end
|
||||
|
||||
-- If the path is a global path, use it directly
|
||||
local sStartChar = string.sub( _sCommand, 1, 1 )
|
||||
if sStartChar == "/" or sStartChar == "\\" then
|
||||
local sPath = fs.combine( "", _sCommand )
|
||||
if fs.exists( sPath ) and not fs.isDir( sPath ) then
|
||||
return sPath
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Otherwise, look on the path variable
|
||||
for sPath in string.gmatch(sPath, "[^:]+") do
|
||||
sPath = fs.combine( shell.resolve( sPath ), _sCommand )
|
||||
if fs.exists( sPath ) and not fs.isDir( sPath ) then
|
||||
return sPath
|
||||
end
|
||||
end
|
||||
|
||||
-- Not found
|
||||
return nil
|
||||
end
|
||||
|
||||
function shell.programs( _bIncludeHidden )
|
||||
local tItems = {}
|
||||
|
||||
-- Add programs from the path
|
||||
for sPath in string.gmatch(sPath, "[^:]+") do
|
||||
sPath = shell.resolve( sPath )
|
||||
if fs.isDir( sPath ) then
|
||||
local tList = fs.list( sPath )
|
||||
for n,sFile in pairs( tList ) do
|
||||
if not fs.isDir( fs.combine( sPath, sFile ) ) and
|
||||
(_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then
|
||||
tItems[ sFile ] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Sort and return
|
||||
local tItemList = {}
|
||||
for sItem, b in pairs( tItems ) do
|
||||
table.insert( tItemList, sItem )
|
||||
end
|
||||
table.sort( tItemList )
|
||||
return tItemList
|
||||
end
|
||||
|
||||
function shell.getRunningProgram()
|
||||
if #tProgramStack > 0 then
|
||||
return tProgramStack[#tProgramStack]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function shell.setAlias( _sCommand, _sProgram )
|
||||
tAliases[ _sCommand ] = _sProgram
|
||||
end
|
||||
|
||||
function shell.clearAlias( _sCommand )
|
||||
tAliases[ _sCommand ] = nil
|
||||
end
|
||||
|
||||
function shell.aliases()
|
||||
-- Add aliases
|
||||
local tCopy = {}
|
||||
for sAlias, sCommand in pairs( tAliases ) do
|
||||
tCopy[sAlias] = sCommand
|
||||
end
|
||||
return tCopy
|
||||
end
|
||||
|
||||
-- Custom shell API functions
|
||||
|
||||
function shell.executeScript(path)
|
||||
if not fs.exists(path) or fs.isDir(path) then
|
||||
return "File or directory not found"
|
||||
else
|
||||
local t = luaex.iterateFileLines(path)
|
||||
if string.find(t[1], "@ @ !! FREAX SCRIPT HEADER") or t[1] == "@ @ !! FREAX SCRIPT HEADER" then
|
||||
for _,cmd in pairs(t) do
|
||||
shell.run(cmd)
|
||||
end
|
||||
else
|
||||
return "Couldn't find script header"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function shell.getActiveUserShell()
|
||||
if fs.exists("/etc/passwd/.shadow/".._G["_activeUser"]..".usr") then
|
||||
local ud = dofile("/etc/passwd/.shadow/".._G["_activeUser"]..".usr")
|
||||
return ud.shell or "/bin/sh"
|
||||
else
|
||||
return "/bin/sh"
|
||||
end
|
||||
end
|
||||
|
||||
-- Run custom shells
|
||||
if findArg("--force") or findArg("-f") then
|
||||
kernel.writeMessage("Ignoring shell settings")
|
||||
elseif shell.getActiveUserShell() ~= "/bin/sh" then
|
||||
shell.run(shell.getActiveUserShell())
|
||||
kernel.shutdown(false)
|
||||
end
|
||||
|
||||
term.setBackgroundColor( bgColour )
|
||||
term.setTextColour( textColour )
|
||||
|
||||
local label = os.getComputerLabel() or os.getComputerID()
|
||||
|
||||
-- Read commands and execute them
|
||||
local tCommandHistory = {}
|
||||
while not bExit do
|
||||
term.setBackgroundColor( bgColour )
|
||||
if security.getSU() then
|
||||
if security.getActiveUserStatus() then
|
||||
term.setTextColour( colours.lime )
|
||||
else
|
||||
term.setTextColour( colours.orange )
|
||||
end
|
||||
else
|
||||
term.setTextColour( colours.cyan )
|
||||
end
|
||||
write( _activeUser )
|
||||
term.setTextColour( colours.lightGrey )
|
||||
write( "@" )
|
||||
term.setTextColour( colours.lightBlue )
|
||||
write( label )
|
||||
term.setTextColour( colours.lightGrey )
|
||||
write( "/" )
|
||||
term.setTextColour( colours.lightBlue )
|
||||
write( shell.dir() )
|
||||
if security.getSU() then
|
||||
if security.getActiveUserStatus() then
|
||||
term.setTextColour( colours.lime )
|
||||
else
|
||||
term.setTextColour( colours.orange )
|
||||
end
|
||||
write( " # " )
|
||||
else
|
||||
term.setTextColour( colours.cyan )
|
||||
write( " $ " )
|
||||
end
|
||||
term.setTextColour( textColour )
|
||||
|
||||
local sLine = read( nil, tCommandHistory )
|
||||
table.insert( tCommandHistory, sLine )
|
||||
runLine( sLine )
|
||||
end
|
||||
|
||||
-- Custom shutdown code goes here
|
3
bin/time
Normal file
3
bin/time
Normal file
|
@ -0,0 +1,3 @@
|
|||
local nTime = os.time()
|
||||
local nDay = os.day()
|
||||
print("The time is " .. textutils.formatTime(nTime, false) .. " on Day " .. nDay)
|
65
bin/tpm-install
Normal file
65
bin/tpm-install
Normal file
|
@ -0,0 +1,65 @@
|
|||
local tArgs = {...}
|
||||
local packages = config.load("/etc/tpm/package.dat")
|
||||
local temp = config.load("/etc/tpm/packageInstalled.dat")
|
||||
local found, value
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo("tpm", "Package name not specified")
|
||||
return
|
||||
elseif not packages then
|
||||
kerneldraw.printAppInfo("tpm", "package.dat is missing or corrupt")
|
||||
log.writeMessage("package.dat unable to be traversed")
|
||||
return
|
||||
elseif not temp then
|
||||
shell.executeScript("/etc/scripts/tpm-recache.tsf")
|
||||
end
|
||||
|
||||
found, value = search.traverseKey(temp, tArgs[1])
|
||||
if found and value then
|
||||
kerneldraw.printAppInfo("tpm", "Package already installed")
|
||||
return
|
||||
end
|
||||
|
||||
kerneldraw.printAppInfo("tpm", "Traversing package.dat")
|
||||
local ok, pack = search.traverseValue(packages, tArgs[1])
|
||||
if ok and pack then
|
||||
kerneldraw.printAppInfo("tpm", "Found corresponding package")
|
||||
kerneldraw.printAppInfo("tpm", "Downloading API files [1/2]")
|
||||
local numapi = 1
|
||||
local numbin = 1
|
||||
local APIInstallFlag = false
|
||||
for k,v in pairs(pack.apis) do
|
||||
if tpm.downloadAPI(k, v) then
|
||||
APIInstallFlag = true
|
||||
kerneldraw.printAppInfo("tpm", "Downloaded API "..k.." ["..tostring(numapi).."]")
|
||||
else
|
||||
kerneldraw.printAppWarning("tpm", "Failed to download API "..k)
|
||||
end
|
||||
numapi = numapi + 1
|
||||
end
|
||||
kerneldraw.printAppInfo("tpm", "Downloading binaries [2/2]")
|
||||
for k,v in pairs(pack.bins) do
|
||||
if tpm.downloadBinary(k, v) then
|
||||
kerneldraw.printAppInfo("tpm", "Downloaded binary "..k.." ["..tostring(numbin).."]")
|
||||
else
|
||||
kerneldraw.printAppWarning("tpm", "Failed to download binary "..k)
|
||||
end
|
||||
numbin = numbin + 1
|
||||
end
|
||||
table.insert(temp, pack.name)
|
||||
log.writeMessage("New package downloaded and installed")
|
||||
config.save(temp, "/etc/tpm/packageInstalled.dat")
|
||||
kerneldraw.printAppSuccess("tpm", "package installed")
|
||||
if APIInstallFlag then
|
||||
if kerneldraw.request("Assemblies were installed, restart") then
|
||||
kernel.reboot(false)
|
||||
end
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("tpm", "Unable to find id for "..tArgs[1])
|
||||
end
|
30
bin/tpm-list
Normal file
30
bin/tpm-list
Normal file
|
@ -0,0 +1,30 @@
|
|||
local tArgs = {...}
|
||||
local packages = config.load("/etc/tpm/package.dat")
|
||||
local packageInstalled = config.load("/etc/tpm/packageInstalled.dat")
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if not packages then
|
||||
kerneldraw.printAppInfo("tpm", "package.dat is missing or corrupt")
|
||||
log.writeMessage("package.dat unable to be traversed")
|
||||
return
|
||||
elseif not packageInstalled then
|
||||
shell.executeScript("/etc/scripts/tpm-recache.tsf")
|
||||
end
|
||||
|
||||
if search.findValue(tArgs, "available") then
|
||||
kerneldraw.printAppInfo("tpm", "Traversing package.dat")
|
||||
for k, v in pairs(packages) do
|
||||
kerneldraw.printAppInfo("tpm", "Found package identifier "..v.name)
|
||||
end
|
||||
elseif search.findValue(tArgs, "installed") then
|
||||
kerneldraw.printAppInfo("tpm", "Traversing packageInstalled.dat")
|
||||
for k, v in pairs(packageInstalled) do
|
||||
kerneldraw.printAppInfo("tpm", "Found package identifier "..v)
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("tpm", "Specify listing type")
|
||||
end
|
13
bin/tpm-recache
Normal file
13
bin/tpm-recache
Normal file
|
@ -0,0 +1,13 @@
|
|||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
kerneldraw.printAppInfo("tpm", "Redownloading package.dat")
|
||||
if tpm.getPaste("/etc/tpm/package.dat", "0YScZtUc", true) then
|
||||
kerneldraw.printAppSuccess("tpm", "Package cache updated")
|
||||
log.writeMessage("Package cache updated")
|
||||
else
|
||||
kerneldraw.printAppInfo("tpm", "Failed to update package cache")
|
||||
log.writeMessage("Failed to update package cache")
|
||||
end
|
68
bin/tpm-remove
Normal file
68
bin/tpm-remove
Normal file
|
@ -0,0 +1,68 @@
|
|||
local tArgs = {...}
|
||||
local packages = config.load("/etc/tpm/package.dat")
|
||||
local temp = config.load("/etc/tpm/packageInstalled.dat")
|
||||
local found, value
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo("tpm", "Package name not specified")
|
||||
return
|
||||
elseif not packages then
|
||||
kerneldraw.printAppInfo("tpm", "package.dat is missing or corrupt")
|
||||
log.writeMessage("package.dat unable to be traversed")
|
||||
return
|
||||
elseif not temp then
|
||||
shell.executeScript("/etc/scripts/tpm-recache.tsf")
|
||||
end
|
||||
|
||||
|
||||
kerneldraw.printAppInfo("tpm", "Traversing package.dat")
|
||||
local ok, pack = search.traverseValue(packages, tArgs[1])
|
||||
if ok and pack then
|
||||
found, value = search.traverseKey(temp, pack.name)
|
||||
if found and value then
|
||||
temp[value] = nil
|
||||
else
|
||||
kerneldraw.printAppInfo("tpm", "Package missing")
|
||||
return
|
||||
end
|
||||
kerneldraw.printAppInfo("tpm", "Found corresponding package")
|
||||
kerneldraw.printAppInfo("tpm", "Removing API files [1/2]")
|
||||
local numapi = 1
|
||||
local numbin = 1
|
||||
local APIRemovalFlag = false
|
||||
for k,v in pairs(pack.apis) do
|
||||
if fs.exists(tpm.toPackageAPI(k)) and not fs.isDir(tpm.toPackageAPI(k)) then
|
||||
fs.delete(tpm.toPackageAPI(k))
|
||||
APIRemovalFlag = true
|
||||
kerneldraw.printAppInfo("tpm", "Removed API "..k.." ["..tostring(numapi).."]")
|
||||
else
|
||||
kerneldraw.printAppWarning("tpm", "Failed to remove API "..k)
|
||||
end
|
||||
numapi = numapi + 1
|
||||
end
|
||||
kerneldraw.printAppInfo("tpm", "Removing binaries [2/2]")
|
||||
for k,v in pairs(pack.bins) do
|
||||
if fs.exists(tpm.toPackageBinary(k)) and not fs.isDir(tpm.toPackageBinary(k)) then
|
||||
fs.delete(tpm.toPackageBinary(k))
|
||||
kerneldraw.printAppInfo("tpm", "Removed binary "..k.." ["..tostring(numbin).."]")
|
||||
else
|
||||
kerneldraw.printAppWarning("tpm", "Failed to remove binary "..k)
|
||||
end
|
||||
numbin = numbin + 1
|
||||
end
|
||||
if APIRemovalFlag then
|
||||
if kerneldraw.request("Assemblies were removed, restart") then
|
||||
kernel.reboot(false)
|
||||
end
|
||||
end
|
||||
config.save(temp, "/etc/tpm/packageInstalled.dat")
|
||||
log.writeMessage("Removed package "..tArgs[1])
|
||||
kerneldraw.printAppSuccess("tpm", "Package removed")
|
||||
else
|
||||
kerneldraw.printAppInfo("tpm", "Unable to find id for "..tArgs[1])
|
||||
end
|
14
bin/tpm-repair
Normal file
14
bin/tpm-repair
Normal file
|
@ -0,0 +1,14 @@
|
|||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if not config.load("/etc/tpm/packageInstalled.dat") then
|
||||
kerneldraw.printAppInfo("tpm", "packageInstalled.dat is missing or corrupt")
|
||||
if kerneldraw.request("Repair TPM data files") then
|
||||
config.save({}, "/etc/tpm/packageInstalled.dat")
|
||||
kerneldraw.printAppInfo("tpm", "Package registry reconstructed")
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("tpm", "packageInstalled.dat is correctly readable")
|
||||
end
|
2
bin/tty
Normal file
2
bin/tty
Normal file
|
@ -0,0 +1,2 @@
|
|||
local x, y = term.getSize()
|
||||
kerneldraw.printAppInfo("tty", "Terminal object size is "..tostring(x).."x"..tostring(y))
|
17
bin/type
Normal file
17
bin/type
Normal file
|
@ -0,0 +1,17 @@
|
|||
local tArgs = { ... }
|
||||
if #tArgs < 1 then
|
||||
local programName = "type"
|
||||
print("Usage: " .. programName .. " <path>")
|
||||
return
|
||||
end
|
||||
|
||||
local sPath = shell.resolve(tArgs[1])
|
||||
if fs.exists(sPath) then
|
||||
if fs.isDir(sPath) then
|
||||
print("directory")
|
||||
else
|
||||
print("file")
|
||||
end
|
||||
else
|
||||
print("No such path")
|
||||
end
|
62
bin/uname
Normal file
62
bin/uname
Normal file
|
@ -0,0 +1,62 @@
|
|||
local tArgs = {...}
|
||||
local err = true
|
||||
local function findArg(arg)
|
||||
for _,v in ipairs(tArgs) do
|
||||
if v == arg then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
if findArg("--help") or findArg("-h") then
|
||||
err = false
|
||||
shell.execute("/bin/man uname")
|
||||
end
|
||||
if findArg("--kernel-name") or findArg("-s") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getName())
|
||||
end
|
||||
if findArg("--nodename") or findArg("-n") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getHostname())
|
||||
end
|
||||
if findArg("--kernel-release") or findArg("-r") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getRelease())
|
||||
end
|
||||
if findArg("--kernel-version") or findArg("-v") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getVersion())
|
||||
end
|
||||
if findArg("--machine") or findArg("-m") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getMachine())
|
||||
end
|
||||
if findArg("--processor") or findArg("-p") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getProcessorArchitecture())
|
||||
end
|
||||
if findArg("--hardware-platform") or findArg("-i") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getHardwarePlatform())
|
||||
end
|
||||
if findArg("--operating-system") or findArg("-o") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", kernel.getOS())
|
||||
end
|
||||
if findArg("--path") or findArg("-b") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", shell.path())
|
||||
end
|
||||
if findArg("--id") or findArg("-c") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", os.getComputerID())
|
||||
end
|
||||
if findArg("--user") or findArg("-u") then
|
||||
err = false
|
||||
kerneldraw.printAppInfo("uname", _G[_activeUser])
|
||||
end
|
||||
if #tArgs < 1 or err then
|
||||
kerneldraw.printAppInfo("uname", "Arguments not specified")
|
||||
end
|
4
bin/unmount
Normal file
4
bin/unmount
Normal file
|
@ -0,0 +1,4 @@
|
|||
if mounter == nil then error("Mounting directories is not supported in vanilla mode.") end
|
||||
local args = { ... }
|
||||
if args[1] ~= nil then if not mounter.unmount(args[1]) then printError("Could not unmount") end
|
||||
else print("Usage: unmount <name>") end
|
25
bin/useradd
Normal file
25
bin/useradd
Normal file
|
@ -0,0 +1,25 @@
|
|||
local tArgs = {...}
|
||||
|
||||
if #tArgs < 2 then
|
||||
kerneldraw.printAppInfo("useradd", "Specify a user")
|
||||
return
|
||||
end
|
||||
|
||||
if fs.exists("/etc/passwd/"..tArgs[1]..".dat") and not fs.isDir("/etc/passwd/"..tArgs[1]..".dat") then
|
||||
kerneldraw.printAppInfo("useradd", "User already exists")
|
||||
return
|
||||
end
|
||||
|
||||
if not security.getSU() then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
if security.passbyte(tArgs[1], tArgs[2]) then
|
||||
kerneldraw.printAppSuccess("useradd", "User "..tArgs[1].." added")
|
||||
log.writeSecurity("User "..tArgs[1].." added")
|
||||
fs.makeDir("/home/"..tArgs[1])
|
||||
else
|
||||
kerneldraw.printAppInfo("useradd", "Failed to add user " .. tArgs[1])
|
||||
log.writeSecurity("Failed to add user " .. tArgs[1])
|
||||
end
|
27
bin/userdel
Normal file
27
bin/userdel
Normal file
|
@ -0,0 +1,27 @@
|
|||
local tArgs = { ... }
|
||||
|
||||
if #tArgs < 1 then
|
||||
kerneldraw.printAppInfo( "userdel", "Specify a user" )
|
||||
return
|
||||
end
|
||||
|
||||
if not security.getSU() or tArgs[1] == "root" then
|
||||
exception.throw("RestrictedOpsException")
|
||||
return
|
||||
end
|
||||
|
||||
local pathA = "/etc/passwd/"..tArgs[1]..".dat"
|
||||
local pathB = "/etc/passwd/.shadow/"..tArgs[1]..".usr"
|
||||
local pathC = "/home/"..tArgs[1]
|
||||
|
||||
if fs.exists(pathA) then
|
||||
if kerneldraw.request("remove user record") then
|
||||
fs.delete( pathA )
|
||||
if fs.exists(pathB) then
|
||||
fs.delete( pathB )
|
||||
end
|
||||
fs.delete( pathC )
|
||||
end
|
||||
else
|
||||
kerneldraw.printAppInfo("userdel", "User " .. tArgs[1] .. " does not exist")
|
||||
end
|
92
bin/wget
Normal file
92
bin/wget
Normal file
|
@ -0,0 +1,92 @@
|
|||
local function printUsage()
|
||||
local programName = "wget"
|
||||
print("Usage:")
|
||||
print(programName .. " <url> [filename]")
|
||||
print(programName .. " run <url>")
|
||||
end
|
||||
|
||||
local tArgs = { ... }
|
||||
|
||||
local run = false
|
||||
if tArgs[1] == "run" then
|
||||
table.remove(tArgs, 1)
|
||||
run = true
|
||||
end
|
||||
|
||||
if #tArgs < 1 then
|
||||
printUsage()
|
||||
return
|
||||
end
|
||||
|
||||
local url = table.remove(tArgs, 1)
|
||||
|
||||
if not http then
|
||||
printError("wget requires the http API")
|
||||
printError("Set http.enabled to true in CC: Tweaked's config")
|
||||
return
|
||||
end
|
||||
|
||||
local function getFilename(sUrl)
|
||||
sUrl = sUrl:gsub("[#?].*" , ""):gsub("/+$" , "")
|
||||
return sUrl:match("/([^/]+)$")
|
||||
end
|
||||
|
||||
local function get(sUrl)
|
||||
-- Check if the URL is valid
|
||||
local ok, err = http.checkURL(url)
|
||||
if not ok then
|
||||
printError(err or "Invalid URL.")
|
||||
return
|
||||
end
|
||||
|
||||
write("Connecting to " .. sUrl .. "... ")
|
||||
|
||||
local response = http.get(sUrl , nil , true)
|
||||
if not response then
|
||||
print("Failed.")
|
||||
return nil
|
||||
end
|
||||
|
||||
print("Success.")
|
||||
|
||||
local sResponse = response.readAll()
|
||||
response.close()
|
||||
return sResponse or ""
|
||||
end
|
||||
|
||||
if run then
|
||||
local res = get(url)
|
||||
if not res then return end
|
||||
|
||||
local func, err = load(res, getFilename(url), "t", _ENV)
|
||||
if not func then
|
||||
printError(err)
|
||||
return
|
||||
end
|
||||
|
||||
local ok, err = pcall(func, table.unpack(tArgs))
|
||||
if not ok then
|
||||
printError(err)
|
||||
end
|
||||
else
|
||||
local sFile = tArgs[1] or getFilename(url) or url
|
||||
local sPath = shell.resolve(sFile)
|
||||
if fs.exists(sPath) then
|
||||
print("File already exists")
|
||||
return
|
||||
end
|
||||
|
||||
local res = get(url)
|
||||
if not res then return end
|
||||
|
||||
local file, err = fs.open(sPath, "wb")
|
||||
if not file then
|
||||
printError("Cannot save file: " .. err)
|
||||
return
|
||||
end
|
||||
|
||||
file.write(res)
|
||||
file.close()
|
||||
|
||||
print("Downloaded as " .. sFile)
|
||||
end
|
6
boot/freax/boot.conf
Normal file
6
boot/freax/boot.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
[ "enableBootScreen" ] = "true",
|
||||
[ "doSystemSetup" ] = "true",
|
||||
[ "logo" ] = "/boot/freax/freax.img",
|
||||
[ "logo_small" ] = "/boot/freax/freax-small.img",
|
||||
}
|
7
boot/freax/freax-small.img
Normal file
7
boot/freax/freax-small.img
Normal file
|
@ -0,0 +1,7 @@
|
|||
aaaaaaaaaaaaaaaaaaa
|
||||
aaa000aaaeeaaeeaaaa
|
||||
aaa0aaaaaaa11aaaaaa
|
||||
aaa000aaaaa44aaaaaa
|
||||
aaa0aaaaaaa55aaaaaa
|
||||
aaa0aaaaa33aa33aaaa
|
||||
aaaaaaaaaaaaaaaaaaa
|
7
boot/freax/freax.img
Normal file
7
boot/freax/freax.img
Normal file
|
@ -0,0 +1,7 @@
|
|||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaa000aaa0000aaa000aaa0000aaaeeaaeeaa
|
||||
aaa0aaaaa0aa0aaa0aaaaa0aa0aaaaa11aaaa
|
||||
aaa000aaa0000aaa000aaa0000aaaaa44aaaa
|
||||
aaa0aaaaa00aaaaa0aaaaa0aa0aaaaa55aaaa
|
||||
aaa0aaaaa0a00aaa000aaa0aa0aaa33aa33aa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
169
boot/freax/initrd.img
Normal file
169
boot/freax/initrd.img
Normal file
|
@ -0,0 +1,169 @@
|
|||
kernel.isBooting = true
|
||||
settings.load("/boot/freax/boot.conf")
|
||||
if not fs.exists(settings.get("logo")) then
|
||||
print("logo is not a valid image")
|
||||
sleep(3)
|
||||
os.reboot()
|
||||
end
|
||||
if not fs.exists(settings.get("logo_small")) then
|
||||
print("logo_small is not a valid image")
|
||||
sleep(3)
|
||||
os.reboot()
|
||||
end
|
||||
local logo = paintutils.loadImage(settings.get("logo"))
|
||||
local slogo = paintutils.loadImage(settings.get("logo_small"))
|
||||
local enableBootScreen = settings.get("enableBootScreen")
|
||||
local doSystemSetup = settings.get("doSystemSetup")
|
||||
if enableBootScreen == "false" then
|
||||
enableBootScreen = false
|
||||
elseif enableBootScreen == "true" then
|
||||
enableBootScreen = true
|
||||
else
|
||||
print("enableBootScreen is a boolean.")
|
||||
sleep(3)
|
||||
kernel.reboot(true)
|
||||
end
|
||||
if doSystemSetup == "false" then
|
||||
doSystemSetup = false
|
||||
elseif doSystemSetup == "true" then
|
||||
doSystemSetup = true
|
||||
else
|
||||
print("doSystemSetup is a boolean.")
|
||||
sleep(3)
|
||||
kernel.reboot(true)
|
||||
end
|
||||
kernel.printLog = not enableBootScreen
|
||||
kernel.writeBootLog("Initializing " .. kernel.getName())
|
||||
kerneldraw.bootScreen(enableBootScreen,0,logo,slogo,"Initializing " .. kernel.getName())
|
||||
kerneldraw.bootDelay(1)
|
||||
kerneldraw.bootScreen(enableBootScreen,0,logo,slogo,"Loading system libraries")
|
||||
kernel.loadSysLibs()
|
||||
local oldReadOnly = _G["fs"]["isReadOnly"]
|
||||
local oldMove = _G["fs"]["move"]
|
||||
local oldDelete = _G["fs"]["delete"]
|
||||
local oldHttpGet = _G["http"]["get"]
|
||||
local oldError = _G["error"]
|
||||
kerneldraw.bootDelay(1)
|
||||
kerneldraw.bootScreen(enableBootScreen,10,logo,slogo,"Initializing logs")
|
||||
kerneldraw.bootDelay(0.5)
|
||||
kernel.writeBootLog("Initialized system boot log")
|
||||
kernel.writeSyslog("Initialized primary system log")
|
||||
kernel.writeMessage("Initialized secondary system log")
|
||||
kerneldraw.bootScreen(enableBootScreen,13,logo,slogo,"Initializing logs")
|
||||
kernel.writeSecurity("Initialized security/access log")
|
||||
kernel.writeShutdown("Initialized shutdown log")
|
||||
kernel.writeAuth("Initialized authorization log")
|
||||
kerneldraw.bootDelay(0.25)
|
||||
kerneldraw.bootScreen(enableBootScreen,15,logo,slogo,"Initializing HTTP")
|
||||
if http then
|
||||
kernel.writeBootLog("HTTP detection succeeded")
|
||||
else
|
||||
kernel.writeBootLog("HTTP detection failed")
|
||||
end
|
||||
kerneldraw.bootDelay(2.1)
|
||||
kerneldraw.bootScreen(enableBootScreen,27,logo,slogo,"Executing autorun")
|
||||
shell.run("/etc/autorun")
|
||||
kerneldraw.bootScreen(enableBootScreen,36,logo,slogo,"Loading user libraries")
|
||||
kernel.loadUsrLibs()
|
||||
kerneldraw.bootDelay(0.25)
|
||||
kerneldraw.bootScreen(enableBootScreen,44,logo,slogo,"Initializing security")
|
||||
kernel.writeBootLog("Initializing security")
|
||||
_G["fs"]["isReadOnly"] = function(path)
|
||||
local find1 = shell.resolve(path)
|
||||
if string.find(find1, "boot") or string.find(find1, "etc") or string.find(find1, "bin") or string.find(find1, "sbin") then
|
||||
kernel.writeSecurity("Attempt to access system files!")
|
||||
if security.getSU() or _IDENTIFIER then
|
||||
kernel.writeSecurity("Superuser access verified.")
|
||||
return false
|
||||
else
|
||||
kernel.writeSecurity("Attempt blocked.")
|
||||
return true
|
||||
end
|
||||
elseif find1 == "initrd" or find1 == "/boot/kernel" then
|
||||
kernel.writeSecurity("Attempt to access bootloader!")
|
||||
kernel.writeSecurity("Attempt blocked.")
|
||||
return true
|
||||
end
|
||||
return oldReadOnly(path)
|
||||
end
|
||||
_G["fs"]["move"] = function(path1, path2)
|
||||
local find2 = shell.resolve(path1)
|
||||
if string.find(find2, "boot") or string.find(find2, "etc") or string.find(find2, "bin") or string.find(find2, "sbin") then
|
||||
kernel.writeSecurity("Attempt to access system files!")
|
||||
if security.getSU() or _IDENTIFIER then
|
||||
kernel.writeSecurity("Superuser access verified.")
|
||||
else
|
||||
kernel.writeSecurity("Attempt blocked.")
|
||||
exception.throw("RestrictedOpsException")
|
||||
return nil
|
||||
end
|
||||
elseif find2 == "initrd" or find2 == "/boot/kernel" then
|
||||
kernel.writeSecurity("Attempt to access bootloader!")
|
||||
kernel.writeSecurity("Attempt blocked.")
|
||||
exception.throw("RestrictedOpsException")
|
||||
return nil
|
||||
end
|
||||
return oldMove(path1, path2)
|
||||
end
|
||||
_G["fs"]["delete"] = function(path)
|
||||
local find3 = shell.resolve(path)
|
||||
if string.find(find3, "boot") or string.find(find3, "etc") or string.find(find3, "bin") or string.find(find3, "sbin") then
|
||||
kernel.writeSecurity("Attempt to access system files!")
|
||||
if security.getSU() or _IDENTIFIER then
|
||||
kernel.writeSecurity("Superuser access verified.")
|
||||
else
|
||||
kernel.writeSecurity("Attempt blocked.")
|
||||
exception.throw("RestrictedOpsException")
|
||||
return nil
|
||||
end
|
||||
elseif find3 == "initrd" or find3 == "/boot/kernel" then
|
||||
kernel.writeSecurity("Attempt to access bootloader!")
|
||||
kernel.writeSecurity("Attempt blocked.")
|
||||
exception.throw("RestrictedOpsException")
|
||||
return nil
|
||||
end
|
||||
return oldDelete(path)
|
||||
end
|
||||
_G["http"]["get"] = function(url, headers)
|
||||
kernel.writeSecurity("Downloaded contents of "..url)
|
||||
return oldHttpGet(url, headers)
|
||||
end
|
||||
_G["error"] = function(text, lvl)
|
||||
local x = lvl or 2
|
||||
local logger = fs.open("/etc/errorLog", "a")
|
||||
logger.writeLine(tostring(os.day()).."d:"..textutils.formatTime(os.time(), true).." | "..text)
|
||||
logger.close()
|
||||
oldError(text, x or 1)
|
||||
end
|
||||
rawset(fs, "_native", {})
|
||||
rawset(fs, "_native.check", oldReadOnly)
|
||||
rawset(fs, "_native.move", oldMove)
|
||||
rawset(fs, "_native.delete", oldDelete)
|
||||
rawset(http, "_synchronise", oldHttpGet)
|
||||
rawset(os, "_exception", oldError)
|
||||
kerneldraw.bootDelay(3.6)
|
||||
kernel.writeBootLog("Boot sequence stage 2 complete")
|
||||
kerneldraw.bootScreen(enableBootScreen,86,logo,slogo,"Finishing")
|
||||
kerneldraw.bootDelay(3)
|
||||
if doSystemSetup then
|
||||
if enableBootScreen then
|
||||
kerneldraw.clearScreen(colors.black)
|
||||
end
|
||||
local isLogsEnabled = kernel.printLog
|
||||
kernel.printLog = true
|
||||
if kernel.setupSystem() then
|
||||
settings.set("doSystemSetup","false")
|
||||
settings.save("/boot/freax/boot.conf")
|
||||
else
|
||||
kernel.printLog = isLogsEnabled
|
||||
kernel.poweroff(true)
|
||||
end
|
||||
kernel.printLog = isLogsEnabled
|
||||
end
|
||||
kerneldraw.bootScreen(enableBootScreen,100,logo,slogo,"Starting login")
|
||||
kerneldraw.bootDelay(0.5)
|
||||
kernel.printLog = true
|
||||
if enableBootScreen then
|
||||
kerneldraw.clearScreen(colors.black)
|
||||
end
|
||||
shell.run("/sbin/login")
|
376
boot/freax/kernel.boot
Normal file
376
boot/freax/kernel.boot
Normal file
|
@ -0,0 +1,376 @@
|
|||
print("freax: loading")
|
||||
|
||||
local printLog = false
|
||||
local isBooting = false
|
||||
|
||||
function setupSystem()
|
||||
kerneldraw.printKernelMessage("Starting system setup")
|
||||
kerneldraw.printKernelMessage("Please enter a new root password")
|
||||
kerneldraw.printKernelAsking("Password:")
|
||||
local passwd = secureInputReturn("")
|
||||
if security.passbyte("root", passwd) then
|
||||
kerneldraw.printKernelMessage("Changed password of the root user")
|
||||
while true do
|
||||
kerneldraw.printKernelMessage("Do you want to add another user?")
|
||||
kerneldraw.printKernelAsking("[y/n]: ")
|
||||
local add_user = "n"
|
||||
add_user = read()
|
||||
if add_user == "y" or add_user == "Y" then
|
||||
local username = nil
|
||||
local password = nil
|
||||
kerneldraw.printKernelAsking("Username: ")
|
||||
username = read()
|
||||
if username == nil or username == "" then
|
||||
kerneldraw.printKernelMessage("Invalid username")
|
||||
break
|
||||
end
|
||||
kerneldraw.printKernelAsking("Password:")
|
||||
password = secureInputReturn("")
|
||||
if password == nil or password == "" then
|
||||
kerneldraw.printKernelMessage("Invalid password")
|
||||
end
|
||||
if security.passbyte(username,password) then
|
||||
log.writeSecurity("User ".. username .." added")
|
||||
fs.makeDir("/home/" .. username)
|
||||
else
|
||||
kerneldraw.printKernelMessage("Failed to add user " .. username)
|
||||
break
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
kerneldraw.printKernelMessage("System setup completed")
|
||||
return true
|
||||
else
|
||||
kerneldraw.printKernelMessage("Failed to change the password. Shutting down in 3 seconds")
|
||||
sleep(3)
|
||||
reboot(true)
|
||||
return(false)
|
||||
end
|
||||
end
|
||||
|
||||
local function initLogger(file)
|
||||
if not fs.isDir("/var") and not fs.exists("/var/log") and not fs.isDir("/var/log") then
|
||||
fs.makeDir("/var")
|
||||
fs.makeDir("/var/log")
|
||||
end
|
||||
return "/var/log/" .. file
|
||||
end
|
||||
|
||||
function halt()
|
||||
writeKernelCall("halt()")
|
||||
sleep(1)
|
||||
writeShutdown("halting")
|
||||
while true do
|
||||
coroutine.create(function() while true do coroutine.yield() end end)
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
|
||||
function poweroff(varDelete)
|
||||
if varDelete then
|
||||
writeKernelCall("poweroff(true)")
|
||||
else
|
||||
writeKernelCall("poweroff(false)")
|
||||
end
|
||||
writeShutdown("Reaching system poweroff")
|
||||
if varDelete then
|
||||
writeShutdown("Removing temporary files")
|
||||
if fs.exists("/var") and fs.isDir("/var") then
|
||||
fs.delete("/var")
|
||||
end
|
||||
sleep(1)
|
||||
end
|
||||
writeShutdown("Reached system poweroff")
|
||||
sleep(1)
|
||||
os.shutdown()
|
||||
halt()
|
||||
end
|
||||
|
||||
function reboot(varDelete)
|
||||
if varDelete then
|
||||
writeKernelCall("reboot(true)")
|
||||
else
|
||||
writeKernelCall("reboot(false)")
|
||||
end
|
||||
writeShutdown("Reaching system reboot")
|
||||
if varDelete then
|
||||
sleep(0.5)
|
||||
writeShutdown("Removing temporary files")
|
||||
if fs.exists("/var") and fs.isDir("/var") then
|
||||
fs.delete("/var")
|
||||
end
|
||||
end
|
||||
writeShutdown("Reached system reboot")
|
||||
sleep(1.5)
|
||||
os.reboot()
|
||||
halt()
|
||||
end
|
||||
|
||||
function panic(text)
|
||||
writeKernelCall("panic(" .. text .. ")")
|
||||
local logger = fs.open("/etc/errorLog", "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | panic! " ..text)
|
||||
logger.close()
|
||||
printError("freax: panic! " .. text)
|
||||
halt()
|
||||
end
|
||||
|
||||
function import(file)
|
||||
writeKernelCall("import(" .. file .. ")")
|
||||
if fs.exists(file) and not fs.isDir(file) then
|
||||
return os.loadAPI(file)
|
||||
else
|
||||
writeSyslog("Failed to load API " .. file)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function require(file) -- A primitive require
|
||||
writeKernelCall("require(" .. file .. ")")
|
||||
if fs.exists(file) and not fs.isDir(file) then
|
||||
return dofile(file)
|
||||
else
|
||||
writeSyslog("Failed to load module " .. file)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function APIHook(t)
|
||||
writeKernelCall("APIHook(" .. t .. ")")
|
||||
if t then
|
||||
return true
|
||||
else
|
||||
-- Not loaded
|
||||
if import("/system/api/" .. t) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function writeKernelCall(calledFunc)
|
||||
--kerneldraw.printKernelMessage("Function called: " .. calledFunc)
|
||||
local logger = fs.open(initLogger("calls"), "a")
|
||||
logger.writeLine(tostring(os.day()) .. "d:" .. textutils.formatTime(os.time(),true) .. " | Function called: " .. calledFunc)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function writeSyslog(text)
|
||||
writeKernelCall("writeSyslog(" .. text .. ")")
|
||||
kerneldraw.printKernelMessage(text)
|
||||
local logger = fs.open(initLogger("syslog"), "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | " ..text)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function writeMessage(text)
|
||||
writeKernelCall("writeMessage(" .. text .. ")")
|
||||
kerneldraw.printKernelMessage(text)
|
||||
local logger = fs.open(initLogger("messages"), "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | " ..text)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function writeSecurity(text)
|
||||
writeKernelCall("writeSecurity(" .. text .. ")")
|
||||
kerneldraw.printKernelMessage(text)
|
||||
local logger = fs.open(initLogger("security"), "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | " ..text)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function writeShutdown(text)
|
||||
writeKernelCall("writeShutdown(" .. text .. ")")
|
||||
kerneldraw.printKernelMessage(text)
|
||||
local logger = fs.open(initLogger("shutdown"), "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | " ..text)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function writeAuth(text)
|
||||
writeKernelCall("writeAuth(" .. text .. ")")
|
||||
kerneldraw.printKernelMessage(text)
|
||||
local logger = fs.open(initLogger("auth"), "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | " ..text)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function writeBootLog(text)
|
||||
writeKernelCall("writeBootLog(" .. text .. ")")
|
||||
kerneldraw.printKernelMessage(text)
|
||||
local logger = fs.open(initLogger("boot"), "a")
|
||||
logger.writeLine(tostring(os.day()).. "d:" ..textutils.formatTime(os.time(), true).. " | " ..text)
|
||||
logger.close()
|
||||
end
|
||||
|
||||
function loadSysLibs()
|
||||
writeKernelCall("loadSysLibs()")
|
||||
writeBootLog("Loading system libraries")
|
||||
local flist = fs.list("/etc/lib")
|
||||
for _, file in ipairs(flist) do
|
||||
sleep(0.25)
|
||||
local returnValue = import("/etc/lib/" ..file)
|
||||
if returnValue then
|
||||
writeSyslog("Library " .. file .. " loaded")
|
||||
else
|
||||
writeSysLog("Library " .. file .. " failed to load")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function loadUsrLibs()
|
||||
writeKernelCall("loadUsrLibs()")
|
||||
writeBootLog("Loading user libraries")
|
||||
local flist = fs.list("/usr/local/lib")
|
||||
for _, file in ipairs(flist) do
|
||||
sleep(0.25)
|
||||
local returnValue = import("/usr/local/lib/" ..file)
|
||||
if returnValue then
|
||||
writeSyslog("Library " .. file .. " loaded")
|
||||
else
|
||||
writeSysLog("Library " .. file .. " failed to load")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function printFile(file)
|
||||
writeKernelCall("printFile(" .. file .. ")")
|
||||
if fs.exists(file) and not fs.isDir(file) then
|
||||
local handle = fs.open(file, "r")
|
||||
local contents = handle.readAll()
|
||||
handle.close()
|
||||
return contents
|
||||
end
|
||||
end
|
||||
|
||||
function getURLContents(url)
|
||||
writeKernelCall("getURLContents(" .. url .. ")")
|
||||
local handlex = http.get(url)
|
||||
local contents = handlex.readAll()
|
||||
handlex.close()
|
||||
return contents
|
||||
end
|
||||
|
||||
function getFile(file, url, overwrite)
|
||||
writeKernelCall("getFile(" .. file .. "," .. url .. "," .. overwrite .. ")")
|
||||
if not fs.exists(file) then
|
||||
local handle = fs.open(file, "w")
|
||||
handle.writeLine(getURLContents(url))
|
||||
handle.close()
|
||||
return true
|
||||
elseif overwrite and not fs.isDir(file) then
|
||||
local handle = fs.open(file, "w")
|
||||
handle.writeLine(getURLContents(url))
|
||||
handle.close()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function secureInput(invite, definition)
|
||||
writeKernelCall("secureInput(" .. invite .. "," .. definition .. ")")
|
||||
write(invite.. " ")
|
||||
local input = read("*")
|
||||
if input == definition then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function secureInputReturn(invite)
|
||||
writeKernelCall("secureInput(" .. invite .. ")")
|
||||
write(invite.. " ")
|
||||
local input = read("*")
|
||||
return input
|
||||
end
|
||||
|
||||
function getName()
|
||||
writeKernelCall("getName()")
|
||||
return "FREAX Kernel"
|
||||
end
|
||||
|
||||
function getVersion()
|
||||
writeKernelCall("getVersion()")
|
||||
return "d0.0.1.0"
|
||||
end
|
||||
|
||||
function getRelease()
|
||||
writeKernelCall("getRelease()")
|
||||
return getName() .. " " .. getVersion()
|
||||
end
|
||||
|
||||
function getMachine()
|
||||
writeKernelCall("getMachine()")
|
||||
if turtle then
|
||||
if commands then
|
||||
return "Command Turtle"
|
||||
elseif term.isColor() then
|
||||
return "Advanced Turtle"
|
||||
else
|
||||
return "Turtle"
|
||||
end
|
||||
elseif pocket then
|
||||
if commands then
|
||||
return "Command Pocket Computer"
|
||||
elseif term.isColor() then
|
||||
return "Advanced Pocket Computer"
|
||||
else
|
||||
return "Pocket Computer"
|
||||
end
|
||||
else
|
||||
if commands then
|
||||
return "Command Computer"
|
||||
elseif term.isColor() then
|
||||
return "Advanced Computer"
|
||||
else
|
||||
return "Computer"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function getProcessorArchitecture()
|
||||
writeKernelCall("getProcessorArchitecture()")
|
||||
return "lua"
|
||||
end
|
||||
|
||||
function getHardwarePlatform()
|
||||
writeKernelCall("getHardwarePlatform()")
|
||||
return "ComputerCraft"
|
||||
end
|
||||
|
||||
function getOS()
|
||||
writeKernelCall("getOS()")
|
||||
return "FREAX"
|
||||
end
|
||||
|
||||
function getHostname()
|
||||
writeKernelCall("getHostname()")
|
||||
if os.getComputerLabel() == nil then
|
||||
return getOS()
|
||||
else
|
||||
return os.getComputerLabel()
|
||||
end
|
||||
end
|
||||
|
||||
function setHostname(hostname)
|
||||
writeKernelCall("setHostname()")
|
||||
local returncode os.setComputerLabel(hostname)
|
||||
kerneldraw.printAppInfo("net","Changed hostname to " .. hostname)
|
||||
kernel.writeMessage("Changed hostname to " .. hostname)
|
||||
return returncode
|
||||
end
|
||||
|
||||
function numRound(num)
|
||||
return num>=0 and math.floor(num+0.5) or math.ceil(num-0.5)
|
||||
end
|
||||
|
||||
function string2table(string_convert)
|
||||
local table = {}
|
||||
string_convert:sub(".",function(c) table.insert(table,c) end)
|
||||
return table
|
||||
end
|
||||
|
||||
print("freax: loaded")
|
286
boot/freax/kerneldraw.boot
Normal file
286
boot/freax/kerneldraw.boot
Normal file
|
@ -0,0 +1,286 @@
|
|||
termw,termh = term.getSize()
|
||||
|
||||
function clearScreen(color)
|
||||
term.setBackgroundColor(color or colors.black)
|
||||
term.setCursorPos(1,1)
|
||||
term.clear()
|
||||
end
|
||||
|
||||
function button(text, x1, x2, y)
|
||||
term.setCursorPos(x1, y)
|
||||
print(text)
|
||||
local a, b, xx, yy = os.pullEvent("mouse_click")
|
||||
if (xx >= x1 and xx <= x2 and yy == y) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function counter(text, y)
|
||||
for i=1,100 do
|
||||
sleep(0.1)
|
||||
term.setCursorPos(1, y)
|
||||
print(text.." ["..tostring(i).."%]")
|
||||
end
|
||||
end
|
||||
|
||||
function drawProgress(txt, y)
|
||||
term.setCursorPos(4, 4)
|
||||
print(txt)
|
||||
term.setCursorPos(1, y)
|
||||
print("[ ]")
|
||||
term.setCursorPos(2, y)
|
||||
textutils.slowPrint("==============================]", 10)
|
||||
end
|
||||
|
||||
function drawProgressAlt(color)
|
||||
term.setCursorPos(4, 10)
|
||||
print("#-------------------------------------------#")
|
||||
term.setCursorPos(4, 11)
|
||||
print("| |")
|
||||
term.setCursorPos(4, 12)
|
||||
print("#-------------------------------------------#")
|
||||
term.setBackgroundColor(color or colors.yellow)
|
||||
term.setCursorPos(5, 11)
|
||||
textutils.slowWrite(" ", 10)
|
||||
term.setBackgroundColor(colors.black)
|
||||
end
|
||||
|
||||
function printColoredTextLine(y, txt, centered,bg, fg)
|
||||
term.setCursorPos(1, y)
|
||||
term.setBackgroundColor(bg or colors.lightGray)
|
||||
term.write(" ")
|
||||
if centered then
|
||||
term.setCursorPos(termw/2-(string.len(txt)/2-1),y)
|
||||
else
|
||||
term.setCursorPos(1, y)
|
||||
end
|
||||
term.setTextColor(fg or colors.black)
|
||||
print(txt)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
|
||||
function printColoredProgressTextLine(y, txt, progress, bgn, fgn, bgp, fgp)
|
||||
if progress >= 101 then
|
||||
kernel.panic("progress can't be over 100 (printColoredProgressTextLine in kerneldraw)")
|
||||
return
|
||||
end
|
||||
local progress_max = termw
|
||||
local progress_cur
|
||||
if progress >= 2 then
|
||||
if progress_max == 51 then
|
||||
progress_cur = kernel.numRound(progress/1.96078431357)
|
||||
else
|
||||
kernel.panic("monitor has a invalid width that hasn't been programmed in (printColoredProgressTextLine in kerneldraw)")
|
||||
return
|
||||
end
|
||||
else
|
||||
progress_cur = progress
|
||||
end
|
||||
local txt_progress = nil
|
||||
local txt_normal = nil
|
||||
local progresstxt_tmp = nil
|
||||
if progress_cur >= 1 then
|
||||
if progress_cur >= string.len(txt)+1 then
|
||||
txt_progress = txt
|
||||
progresstxttmp = progress_cur-string.len(txt)
|
||||
repeat
|
||||
txt_progress = txt_progress .. " "
|
||||
until progresstxttmp <= 0
|
||||
else
|
||||
txt_progress = string.sub(txt,1,progress_cur)
|
||||
txt_normal = string.sub(txt,progress_cur,string.len(txt))
|
||||
end
|
||||
else
|
||||
txt_progress = ""
|
||||
txt_normal = txt
|
||||
end
|
||||
term.setCursorPos(1,1)
|
||||
term.setBackgroundColor(colors.gray)
|
||||
term.setTextColor(colors.white)
|
||||
print("progress:" .. progress)
|
||||
print("progress_max:" .. progress_max)
|
||||
print("progress_cur:" .. progress_cur)
|
||||
print("txt_progress:" .. txt_progress)
|
||||
print("txt_normal:" .. txt_normal)
|
||||
term.setCursorPos(1, y)
|
||||
term.setBackgroundColor(bgn or colors.purple)
|
||||
term.write(" ")
|
||||
term.setCursorPos(1, y)
|
||||
term.setTextColor(fgp or colors.black)
|
||||
term.setBackgroundColor(bgp or colors.white)
|
||||
print(txt_progress)
|
||||
if not txt_progress == "" then
|
||||
term.setCursorPos(string.len(txt_progress)+1,y)
|
||||
end
|
||||
term.setTextColor(fgn or colors.white)
|
||||
term.setBackgroundColor(bgn or colors.purple)
|
||||
print(txt_normal)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
|
||||
function printBootInfo(i)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.lightGray)
|
||||
write("")
|
||||
term.setTextColor(colors.cyan)
|
||||
write("*")
|
||||
term.setTextColor(colors.lightGray)
|
||||
write(" ")
|
||||
print(" "..i)
|
||||
term.setTextColor(colors.white)
|
||||
if log then
|
||||
log.writeBootLog(i)
|
||||
end
|
||||
end
|
||||
|
||||
function printBootWarning(w)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.lightGray)
|
||||
write("")
|
||||
term.setTextColor(colors.orange)
|
||||
write("!")
|
||||
term.setTextColor(colors.lightGray)
|
||||
write(" ")
|
||||
print(" "..w)
|
||||
term.setTextColor(colors.white)
|
||||
if log then
|
||||
log.writeBootLog(w)
|
||||
end
|
||||
end
|
||||
|
||||
function printBootSuccess(wa)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.lightGray)
|
||||
write("")
|
||||
term.setTextColor(colors.lime)
|
||||
write("v")
|
||||
term.setTextColor(colors.lightGray)
|
||||
write(" ")
|
||||
print(" "..wa)
|
||||
term.setTextColor(colors.white)
|
||||
if log then
|
||||
log.writeBootLog(wa)
|
||||
end
|
||||
end
|
||||
|
||||
function printAppInfo(header, msg)
|
||||
term.setTextColor(colors.cyan)
|
||||
write(header..": ")
|
||||
term.setTextColor(colors.lightGray)
|
||||
print(msg)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
|
||||
function printAppWarning(header, msg)
|
||||
term.setTextColor(colors.red)
|
||||
write(header..": ")
|
||||
term.setTextColor(colors.orange)
|
||||
print(msg)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
|
||||
function printAppSuccess(header, msg)
|
||||
term.setTextColor(colors.lime)
|
||||
write(header..": ")
|
||||
term.setTextColor(colors.green)
|
||||
print(msg)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
|
||||
function printKernelMessage(msg)
|
||||
if kernel.printLog then
|
||||
term.setTextColor(colors.blue)
|
||||
write("freax: ")
|
||||
term.setTextColor(colors.lightBlue)
|
||||
print(msg)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
end
|
||||
|
||||
function printKernelAsking(msg)
|
||||
if kernel.printLog then
|
||||
term.setTextColor(colors.blue)
|
||||
write("freax: ")
|
||||
term.setTextColor(colors.lightBlue)
|
||||
write(msg)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
end
|
||||
|
||||
function request(req)
|
||||
while true do
|
||||
term.setTextColor(colors.cyan)
|
||||
write(req .. "? ")
|
||||
term.setTextColor(colors.lightGray)
|
||||
write("(")
|
||||
term.setTextColor(colors.lime)
|
||||
write("Y")
|
||||
term.setTextColor(colors.lightGray)
|
||||
write("/")
|
||||
term.setTextColor(colors.red)
|
||||
write("N")
|
||||
term.setTextColor(colors.lightGray)
|
||||
write(") ")
|
||||
local presel=read()
|
||||
if presel=="Y" or presel=="y" then
|
||||
return true
|
||||
elseif presel=="N" or presel=="n" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function drawImg(path, x, y)
|
||||
if fs.exists(path) and not fs.isDir(path) then
|
||||
local img = paintutils.loadImage(path)
|
||||
paintutils.drawImage(img, x, y)
|
||||
else
|
||||
printAppWarning("gui", "Image not found")
|
||||
end
|
||||
end
|
||||
|
||||
function drawImgArg(img, x, y)
|
||||
paintutils.drawImage(img, x, y)
|
||||
end
|
||||
|
||||
function printColored(text, color)
|
||||
local tmp = term.getTextColor()
|
||||
term.setTextColor(color)
|
||||
print(text)
|
||||
term.setTextColor(tmp)
|
||||
end
|
||||
|
||||
function bootScreen(enable,progress,logo,logo_small,txt)
|
||||
if enable then
|
||||
clearScreen(colors.black)
|
||||
local check_size = termw
|
||||
local logo_size = 38
|
||||
local logo_small_size = 20
|
||||
if check_size == logo_size then
|
||||
drawImgArg(logo, 1,5)
|
||||
elseif check_size >= logo_size then
|
||||
drawImgArg(logo, (termw/2)-(logo_size/2)+1, 5)
|
||||
elseif check_size == logo_small_size then
|
||||
drawImgArg(logo_small, 1,5)
|
||||
elseif check_size >= logo_small_size then
|
||||
drawImgArg(logo_small, (termw/2)-(logo_small_size/2)+1, 5)
|
||||
end
|
||||
printColoredTextLine(termh-1, txt, true, colors.black, colors.white)
|
||||
--printColoredProgressTextLine(termh-1, txt, progress, colors.black, colors.white, colors.purple, colors.white)
|
||||
--printColoredProgressTextLine(termh-1, txt, progress)
|
||||
end
|
||||
end
|
||||
|
||||
function bootDelay(delay)
|
||||
local enableSleeps = true -- Disabled sleeps
|
||||
local enableDisabledSleep = false -- Disables 0.1 sleep when disabled
|
||||
if enableSleeps then
|
||||
sleep(delay)
|
||||
elseif enableDisabledSleep then
|
||||
sleep(0.1)
|
||||
end
|
||||
end
|
83
boot/ofbl
Normal file
83
boot/ofbl
Normal file
|
@ -0,0 +1,83 @@
|
|||
--rawset(_G, "nativepullevent", os.pullEvent)
|
||||
os.pullEvent = os.pullEventRaw
|
||||
|
||||
enableSleeps = true
|
||||
function string2table(string_convert)
|
||||
local table = {}
|
||||
string_convert:sub(".",function(c) table.insert(table,c) end)
|
||||
return table
|
||||
end
|
||||
|
||||
if not term.isColour() then
|
||||
printError("ofbl: OFBL and FREAX only supports")
|
||||
printError("ofbl: advanced (pocket) computers")
|
||||
sleep(3)
|
||||
os.shutdown()
|
||||
end
|
||||
print("ofbl: conf: Loading")
|
||||
if enableSleeps then sleep(0.3) else sleep(0.1) end
|
||||
local config = {}
|
||||
local name = nil
|
||||
local initrd = nil
|
||||
local kernel = nil
|
||||
local kerneldraw = nil
|
||||
if fs.exists("/boot/ofbl.conf") then
|
||||
settings.load("/boot/ofbl.conf")
|
||||
--config.oslist = string2table(settings.get("oslist"))
|
||||
name = settings.get("os0.name")
|
||||
initrd = settings.get("os0.initrd")
|
||||
kernel = settings.get("os0.kernel")
|
||||
kerneldraw = settings.get("os0.kerneldraw")
|
||||
if name == nil then
|
||||
print("ofbl: conf: name is null")
|
||||
return
|
||||
end
|
||||
if initrd == nil then
|
||||
print("ofbl: conf: initrd is null")
|
||||
return
|
||||
end
|
||||
if kernel == nil then
|
||||
print("ofbl: conf: kernel is null")
|
||||
return
|
||||
end
|
||||
if kerneldraw == nil then
|
||||
print("ofbl: conf: kerneldraw is null")
|
||||
return
|
||||
end
|
||||
else
|
||||
print("ofbl: conf: Not found")
|
||||
return
|
||||
end
|
||||
print("ofbl: Copying kernel and initrd.img into RAM")
|
||||
if enableSleeps then sleep(0.1) else sleep(0.1) end
|
||||
fs.delete("/var/boot")
|
||||
if not fs.isDir("/var") and not fs.exists("/var/boot") and not fs.isDir("/var/boot") then
|
||||
fs.makeDir("/var")
|
||||
fs.makeDir("/var/boot")
|
||||
end
|
||||
if fs.exists(kernel) then
|
||||
if fs.exists(kerneldraw) then
|
||||
if fs.exists(initrd) then
|
||||
fs.copy(initrd,"/var/boot/initrd")
|
||||
fs.copy(kernel,"/var/boot/kernel")
|
||||
fs.copy(kerneldraw,"/var/boot/kerneldraw")
|
||||
else
|
||||
print("ofbl: " .. initrd .. " not found")
|
||||
return
|
||||
end
|
||||
else
|
||||
print("ofbl: " .. kerneldraw .. " not found")
|
||||
return
|
||||
end
|
||||
else
|
||||
print("ofbl: " .. kernel .. " not found")
|
||||
return
|
||||
end
|
||||
if enableSleeps then sleep(1.95) else sleep(0.1) end
|
||||
print("ofbl: Loading kernel")
|
||||
if enableSleeps then sleep(3.25) else sleep(0.1) end
|
||||
os.loadAPI("/var/boot/kernel")
|
||||
os.loadAPI("/var/boot/kerneldraw")
|
||||
print("ofbl: Loading initrd.img")
|
||||
if enableSleeps then sleep(2.65) else sleep(0.1) end
|
||||
shell.execute(initrd)
|
7
boot/ofbl.conf
Normal file
7
boot/ofbl.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
[ "oslist"] = "0",
|
||||
[ "os0.name" ] = "FREAX",
|
||||
[ "os0.initrd" ] = "/boot/freax/initrd.img",
|
||||
[ "os0.kernel" ] = "/boot/freax/kernel.boot",
|
||||
[ "os0.kerneldraw" ] = "/boot/freax/kerneldraw.boot",
|
||||
}
|
8
etc/autorun
Normal file
8
etc/autorun
Normal file
|
@ -0,0 +1,8 @@
|
|||
local oldPath = shell.path()
|
||||
shell.setPath(":/bin:/sbin:/etc/script_util:/usr/bin:/usr/local/bin")
|
||||
|
||||
local link = config.load("/etc/link.dat")
|
||||
|
||||
for k,v in pairs(link) do
|
||||
shell.setAlias(k, v)
|
||||
end
|
2
etc/errorLog
Normal file
2
etc/errorLog
Normal file
|
@ -0,0 +1,2 @@
|
|||
207d:19:39 | Cannot serialize type function
|
||||
208d:6:38 | 1
|
22
etc/lib/config
Normal file
22
etc/lib/config
Normal file
|
@ -0,0 +1,22 @@
|
|||
function load(path)
|
||||
if fs.exists(path) and not fs.isDir(path) then
|
||||
local lf = fs.open(path, "r")
|
||||
local contents = lf.readAll()
|
||||
lf.close()
|
||||
return textutils.unserialize(contents)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function save(cTable, path)
|
||||
if fs.exists(path) then
|
||||
if fs.isDir(path) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local sf = fs.open(path, "w")
|
||||
sf.write(textutils.serialize(cTable))
|
||||
sf.close()
|
||||
return true
|
||||
end
|
26
etc/lib/exception
Normal file
26
etc/lib/exception
Normal file
|
@ -0,0 +1,26 @@
|
|||
local instances = {}
|
||||
|
||||
instances.GenericException = function(text)
|
||||
kerneldraw.printAppWarning(fs.getName(shell.getRunningProgram()), text)
|
||||
log.writeSecurity(text)
|
||||
end
|
||||
|
||||
instances.RestrictedOpsException = function(a)
|
||||
b = a or " "
|
||||
kerneldraw.printAppWarning("kernel", "Attempt to perform restricted operations")
|
||||
log.writeSecurity("Attempt to perform restricted operations")
|
||||
log.writeSecurity("Attempt blocked.")
|
||||
end
|
||||
|
||||
instances.SecurityException = function(path)
|
||||
kerneldraw.printAppWarning("kernel", "Attempt to perform restricted operations")
|
||||
log.writeSecurity(_activeUser.." Attempted to open restricted file at "..path)
|
||||
end
|
||||
|
||||
function throw(exception, arg)
|
||||
if instances[exception] then
|
||||
instances[exception](arg)
|
||||
else
|
||||
instances.GenericException("Exception not found")
|
||||
end
|
||||
end
|
8
etc/lib/log
Normal file
8
etc/lib/log
Normal file
|
@ -0,0 +1,8 @@
|
|||
-- this is a compatibility file for supporting kernel-mode logging
|
||||
|
||||
writeSyslog = kernel.writeSyslog
|
||||
writeMessage = kernel.writeMessage
|
||||
writeSecurity = kernel.writeSecurity
|
||||
writeShutdown = kernel.writeShutdown
|
||||
writeAuth = kernel.writeAuth
|
||||
writeBootLog = kernel.writeBootLog
|
31
etc/lib/luaex
Normal file
31
etc/lib/luaex
Normal file
|
@ -0,0 +1,31 @@
|
|||
function stringToByteArray(str)
|
||||
return string.byte(str, 1, str:len())
|
||||
end
|
||||
|
||||
function argsToTable(...)
|
||||
return { ... }
|
||||
end
|
||||
|
||||
function stringFromByteArray(...)
|
||||
return string.char(...)
|
||||
end
|
||||
|
||||
function iterateFileLines(path)
|
||||
local handle = fs.open(path, "r")
|
||||
local commands = {}
|
||||
local line = handle.readLine()
|
||||
while line do
|
||||
commands[#commands + 1] = line
|
||||
line = handle.readLine()
|
||||
end
|
||||
handle.close()
|
||||
return commands
|
||||
end
|
||||
|
||||
local function string_separate(str)
|
||||
local t = {}
|
||||
for i in string.gmatch(str, "[A-z]") do
|
||||
table.insert(t, i)
|
||||
end
|
||||
return t
|
||||
end
|
12
etc/lib/man
Normal file
12
etc/lib/man
Normal file
|
@ -0,0 +1,12 @@
|
|||
function findManual(name)
|
||||
local flist = fs.list("/etc/manuals")
|
||||
for _, file in ipairs(flist) do
|
||||
if not fs.isDir("/etc/manuals/"..file) and file == name then
|
||||
local handle = fs.open("/etc/manuals/"..file, "r")
|
||||
local contents = handle.readAll()
|
||||
handle.close()
|
||||
return contents
|
||||
end
|
||||
end
|
||||
return "No manual available"
|
||||
end
|
70
etc/lib/net
Normal file
70
etc/lib/net
Normal file
|
@ -0,0 +1,70 @@
|
|||
local isOnline = false
|
||||
|
||||
function getHTTP(url)
|
||||
local handlex = http.get(url)
|
||||
local contents = handlex.readAll()
|
||||
handlex.close()
|
||||
return contents
|
||||
end
|
||||
|
||||
function openModems()
|
||||
for n,sModem in ipairs( peripheral.getNames() ) do
|
||||
if peripheral.getType( sModem ) == "modem" then
|
||||
if not rednet.isOpen( sModem ) then
|
||||
rednet.open( sModem )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function closeModems()
|
||||
for n,sModem in ipairs( peripheral.getNames() ) do
|
||||
if peripheral.getType( sModem ) == "modem" then
|
||||
if rednet.isOpen( sModem ) then
|
||||
rednet.close( sModem )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function getModemStatus(side)
|
||||
kerneldraw.printAppInfo("net", side .. " modem status: " .. tostring(rednet.isOpen(side)))
|
||||
return rednet.isOpen(side)
|
||||
end
|
||||
|
||||
-- DNS self-hosting functions
|
||||
|
||||
function setWorkstationStatus(state)
|
||||
if state == true and isOnline == false then
|
||||
local label = os.getComputerLabel() or kernel.getOS()
|
||||
rednet.host("freax_dns", tostring(os.getComputerID()).."_"..label)
|
||||
isOnline = true
|
||||
log.writeSyslog("Now susceptible for DNS lookup")
|
||||
log.writeMessage("Assigned DNS label "..tostring(os.getComputerID()).."_"..label)
|
||||
elseif state == false and isOnline == true then
|
||||
local label = os.getComputerLabel or kernel.getOS()
|
||||
rednet.host("freax_dns", tostring(os.getComputerID()).."_"..label)
|
||||
isOnline = false
|
||||
log.writeSyslog("No longer susceptible for DNS lookup")
|
||||
log.writeMessage("De-assigned DNS label "..tostring(os.getComputerID()).."_"..label)
|
||||
elseif state == true and isOnline == true then
|
||||
kerneldraw.printAppWarning("net", "workstation already online")
|
||||
elseif state == false and isOnline == false then
|
||||
kerneldraw.printAppWarning("net", "workstation already offline")
|
||||
else
|
||||
log.writeSyslog("RedNet interface error")
|
||||
return nil, "Error in RNI, please consult developer"
|
||||
end
|
||||
end
|
||||
|
||||
function getWorkstationStatus()
|
||||
return isOnline
|
||||
end
|
||||
|
||||
function findWorkstation(query)
|
||||
if rednet.lookup("freax_dns", query) ~= nil then
|
||||
return true, rednet.lookup("freax_dns", query)
|
||||
else
|
||||
return false, nil
|
||||
end
|
||||
end
|
53
etc/lib/search
Normal file
53
etc/lib/search
Normal file
|
@ -0,0 +1,53 @@
|
|||
function traverseKey(array, text)
|
||||
for k,v in pairs(array) do
|
||||
if v == text then
|
||||
return true, k
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function traverseValue(array, text)
|
||||
for k,v in pairs(array) do
|
||||
if k == text then
|
||||
return true, v
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function findKey(array, text)
|
||||
for k,v in pairs(array) do
|
||||
if k == text then
|
||||
return true, k
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function findValue(array, text)
|
||||
for k,v in pairs(array) do
|
||||
if v == text then
|
||||
return true, v
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function queryForKey(array, text)
|
||||
for k,v in pairs(array) do
|
||||
if string.find(k, text) then
|
||||
return true, k
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function queryForValue(array, text)
|
||||
for k,v in pairs(array) do
|
||||
if string.find(v, text) then
|
||||
return true, v
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
42
etc/lib/security
Normal file
42
etc/lib/security
Normal file
|
@ -0,0 +1,42 @@
|
|||
local _IDENTIFIER = "ac30527de6170b7d545bdc152f76237276537f2cf8eb7fe5bdb2a7627f48cec1"
|
||||
|
||||
function getSU()
|
||||
if fs.exists("/etc/passwd/.shadow/".._G["_activeUser"]..".usr") then
|
||||
local ud = dofile("/etc/passwd/.shadow/".._G["_activeUser"]..".usr")
|
||||
return ud.SU
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function getID()
|
||||
return _IDENTIFIER
|
||||
end
|
||||
|
||||
function getActiveUserStatus()
|
||||
if fs.exists("/etc/passwd/.shadow/".._G["_activeUser"]..".usr") then
|
||||
local ud = dofile("/etc/passwd/.shadow/".._G["_activeUser"]..".usr")
|
||||
if ud.ID == getID() then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function passbyte(username, str)
|
||||
passTable = luaex.argsToTable(luaex.stringToByteArray(str))
|
||||
if config.save(passTable, "/etc/passwd/"..username..".dat") then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function unpassbyte(username)
|
||||
passTable = config.load("/etc/passwd/"..username..".dat")
|
||||
if passTable ~= nil then
|
||||
return luaex.stringFromByteArray(unpack(passTable))
|
||||
end
|
||||
end
|
25
etc/lib/tpm
Normal file
25
etc/lib/tpm
Normal file
|
@ -0,0 +1,25 @@
|
|||
function getPaste(file, id, overwrite)
|
||||
if overwrite and fs.exists(file) and string.find(file, "system/") then
|
||||
if fs.exists("/etc/.backups/"..file) then
|
||||
fs.delete("/etc/.backups/"..file)
|
||||
end
|
||||
fs.copy(file, "/etc/.backups/"..file)
|
||||
end
|
||||
return kernel.getFile(file, "http://pastebin.com/raw/"..id, overwrite)
|
||||
end
|
||||
|
||||
function downloadAPI(filename, id)
|
||||
return getPaste("/usr/local/lib/"..filename, id, true)
|
||||
end
|
||||
|
||||
function downloadBinary(filename, id)
|
||||
return getPaste("/usr/local/bin/"..filename, id, true)
|
||||
end
|
||||
|
||||
function toPackageAPI(filename)
|
||||
return "/usr/local/lib/"..filename
|
||||
end
|
||||
|
||||
function toPackageBinary(filename)
|
||||
return "/usr/local/bin/"..filename
|
||||
end
|
1
etc/link.dat
Normal file
1
etc/link.dat
Normal file
|
@ -0,0 +1 @@
|
|||
{["lua"]="/bin/lsh",["username"]="/bin/uname --user",["whoami"]="/bin/uname --user",["help"]="/bin/man",["shell"]="/bin/sh",["sh"]="/bin/sh",["bash"]="/bin/sh",["cash"]="/bin/sh",["shutdown"]="/sbin/shutdown",["reboot"]="/sbin/reboot",["mv"]="/bin/move",["cp"]="/bin/cp",}
|
10
etc/manuals/api-config
Normal file
10
etc/manuals/api-config
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
The Configuration API deals with configuration
|
||||
files: it loads and saves tables into files.
|
||||
|
||||
It has two functions:
|
||||
config.load(path)
|
||||
config.save(tableToSave, path)
|
||||
|
||||
Configuration files are usually marked by the
|
||||
'.conf' extension.
|
4
etc/manuals/api-custom
Normal file
4
etc/manuals/api-custom
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
The 'Custom API' is used to add functions and
|
||||
values to the runtime environment without much
|
||||
hard work ('man custom-api').
|
17
etc/manuals/api-gui
Normal file
17
etc/manuals/api-gui
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
The Graphical User Interface API is responsible
|
||||
for all the colorful text and interface elements
|
||||
of FREAX and has the following functions:
|
||||
button(txt, x1, x2, y)
|
||||
counter(txt, y)
|
||||
drawProgress(txt, y) / drawProgressAlt()
|
||||
printBootInfo(i)
|
||||
printBootWarning(w)
|
||||
printBootSuccess(s)
|
||||
printAppInfo(header, msg)
|
||||
printAppWarning(header, msg)
|
||||
printAppSuccess(header, msg)
|
||||
request(text)
|
||||
drawImg(path, x. y)
|
||||
printColoredTextLine(y, txt, bg, fg)
|
||||
clearScreen(bgColor)
|
25
etc/manuals/api-kernel
Normal file
25
etc/manuals/api-kernel
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
The Kernel API is the one that backs the whole
|
||||
Operating System. It provides wrappers for some
|
||||
in-built functions, and is responsible for
|
||||
error report generation.
|
||||
|
||||
Functions in the Kernel API:
|
||||
credits()
|
||||
getName()
|
||||
getRelease()
|
||||
getVersion()
|
||||
getMachine()
|
||||
getProcessorArchitecture()
|
||||
getHardwarePlatform()
|
||||
getOS()
|
||||
clear()
|
||||
panic(text)
|
||||
import(file) (A safe os.loadAPI)
|
||||
require(file) (A primitive require function)
|
||||
APIHook(api)
|
||||
printFile(file)
|
||||
secureInput(invite, definition)
|
||||
shutdown(removeVar) / reboot(removeVar)
|
||||
findManual(name) (Find a manual file path)
|
||||
The Logging API ('man api-log') functions
|
12
etc/manuals/api-log
Normal file
12
etc/manuals/api-log
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
The Logging API serves as a log file
|
||||
handler.
|
||||
Logs are viewed through dmesg ('man dmesg')
|
||||
|
||||
Functions with corresponding files:
|
||||
writeAuth(msg) -> /var/log/auth
|
||||
writeBootLog(msg) -> /var/log/boot
|
||||
writeMessage(msg) -> /var/log/messages
|
||||
writeSyslog(msg) -> /var/log/syslog
|
||||
writeSecurity(msg) -> /var/log/security
|
||||
writeShutdown(msg) -> /var/log/shutdown
|
8
etc/manuals/api-luaex
Normal file
8
etc/manuals/api-luaex
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
The LuaEx API is used to add new miscellaneous
|
||||
features to the runtime environment.
|
||||
|
||||
Functions:
|
||||
stringToByteArray(str)
|
||||
argsToTable(...)
|
||||
stringFromByteArray(byteArrayTable)
|
9
etc/manuals/api-search
Normal file
9
etc/manuals/api-search
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
The Search API simplifies searching in key-value
|
||||
arrays.
|
||||
|
||||
Functions:
|
||||
traverseKey(table, text)
|
||||
traverseValue(table, text)
|
||||
findKey(table, text)
|
||||
findValue(table, text)
|
9
etc/manuals/api-security
Normal file
9
etc/manuals/api-security
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
The Security API serves as a credential handler,
|
||||
and is responsible for user creation and
|
||||
identification.
|
||||
|
||||
Functions:
|
||||
passbyte(username, password)
|
||||
unpassbyte(username)
|
||||
getSU()
|
8
etc/manuals/api-tpm
Normal file
8
etc/manuals/api-tpm
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
The FREAX Package Management API is used to
|
||||
simplify Pastebin handling and file downloads.
|
||||
|
||||
Functions:
|
||||
getPaste(file, id, overwrite)
|
||||
downloadAPI(file, id) / downloadBinary(file, id)
|
||||
toPackageAPI(filename) / toPackageBinary(filename)
|
17
etc/manuals/archiver
Normal file
17
etc/manuals/archiver
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
archiver <...> [...]
|
||||
|
||||
Required: mode (zip/unzip)
|
||||
directory to zip/archive to unzip
|
||||
archive file name/path to unzip
|
||||
Modes: zip (creates an archive)
|
||||
unzip (unpacks an archive)
|
||||
|
||||
If using the zip mode you can specify two
|
||||
directories the archiver will skip after
|
||||
the required parameters.
|
||||
|
||||
(c) 1Ridav.
|
||||
This is the only third-party program that
|
||||
FREAX is using. It is, however,
|
||||
not a required part of the system.
|
11
etc/manuals/auth
Normal file
11
etc/manuals/auth
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
The authorization system is one of the FREAX
|
||||
security measures.
|
||||
|
||||
Credentials are handled with optimal security.
|
||||
|
||||
Each user has a home directory (/home/<username>)
|
||||
and a credentials identifier used to determine
|
||||
the user's privileges.
|
||||
|
||||
See 'man usrutils' for account management programs.
|
18
etc/manuals/boot-sequence
Normal file
18
etc/manuals/boot-sequence
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
The FREAX Boot Sequence consists of 4 steps:
|
||||
(OFBL stands for Open FREAX Boot Loader)
|
||||
|
||||
1 - The boot sequence is initiated.
|
||||
OFBL is launched and APIs
|
||||
are loaded into the global environment.
|
||||
|
||||
2 - The boot loader handles control to the
|
||||
preferred bootloader record that executes
|
||||
high-level routines (More: 'man custom-boot').
|
||||
|
||||
Assuming that the user prefers the default record:
|
||||
|
||||
3 - Autorun files are handled, and all the code
|
||||
inside of them is executed.
|
||||
|
||||
4 - The FREAX shell is launched.
|
7
etc/manuals/categories
Normal file
7
etc/manuals/categories
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
Some manuals belong to categories.
|
||||
|
||||
Here they are:
|
||||
|
||||
api - FREAX APIs
|
||||
custom - customization
|
15
etc/manuals/changelog
Normal file
15
etc/manuals/changelog
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
Build d0.0.1.0 | DEVELOP changelog:
|
||||
|
||||
! Fixed bugs !
|
||||
+ Added new kernel calls
|
||||
* Renamed references from Tesseract
|
||||
to FREAX
|
||||
* Combined sysinfo and uname
|
||||
* Updated uname to include new
|
||||
kernel calls
|
||||
* Modified boot logo
|
||||
* Updated passwd
|
||||
* Updated many man pages
|
||||
* Updated messages
|
||||
- Removed old uname and sysinfo
|
7
etc/manuals/config
Normal file
7
etc/manuals/config
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
FREAX Configuration Files are handled by the
|
||||
Configuration API (man api-config). They are used
|
||||
to write easily accessible data to disk and access
|
||||
it when necessary.
|
||||
|
||||
Actually, they are just serialized Lua tables.
|
6
etc/manuals/convert
Normal file
6
etc/manuals/convert
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
convert <path>
|
||||
|
||||
Converts an API-like configuration file to a
|
||||
serializable .conf/.dat file. Does not assign
|
||||
extension automatically.
|
15
etc/manuals/coreutils
Normal file
15
etc/manuals/coreutils
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
As the GNU/Linux systems, FREAX also has its
|
||||
own coreutils package.
|
||||
|
||||
cat <file> - prints out a file
|
||||
credits - prints out credits
|
||||
dmesg (...) - displays logs ('man dmesg')
|
||||
df <size> - displays filesystem stats ('man df')
|
||||
man <manual page> - displays help ('man man')
|
||||
scp <path> - copies a file to /home
|
||||
shell - FREAX shell
|
||||
shutdown - performs shutdown
|
||||
uname (...) - shows stats ('man uname')
|
||||
tty - displays terminal size
|
||||
|
16
etc/manuals/credits
Normal file
16
etc/manuals/credits
Normal file
|
@ -0,0 +1,16 @@
|
|||
FREAX Operating System
|
||||
Made by
|
||||
- JeremyStarTM (Maintainer)
|
||||
|
||||
Licensed under GNU GPLv3
|
||||
|
||||
|
||||
Thanks to the Tesseract devs!
|
||||
FREAX is a fork of Tesseract.
|
||||
Tesseract developers:
|
||||
- minebuild02 (Head Developer)
|
||||
- MasatoBaito (Assistant Developer)
|
||||
|
||||
Special thanks to:
|
||||
- 1Ridav (Developer of the DCC Archiver)
|
||||
- Luca_S (Developer of the script parser base)
|
8
etc/manuals/custom
Normal file
8
etc/manuals/custom
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
'custom-boot': Customizing the boot sequence
|
||||
|
||||
'custom-build': Building your own Tesseract OS
|
||||
|
||||
'custom-tpm': Creating your own package.dat
|
||||
|
||||
'custom-script': Automating tasks
|
11
etc/manuals/custom-autorun
Normal file
11
etc/manuals/custom-autorun
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
User autorun files can be used to perform various
|
||||
boot actions while not altering any boot sequence
|
||||
mechanisms.
|
||||
|
||||
This should not be confused with the system autorun
|
||||
file ('/system/autorun'), that is used to perform
|
||||
post-boot initialization actions.
|
||||
|
||||
User autorun files are located in
|
||||
/home/<username>/autorun
|
16
etc/manuals/custom-boot
Normal file
16
etc/manuals/custom-boot
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
You can customize the boot sequence of FREAX
|
||||
in two different ways:
|
||||
|
||||
1. Writing a user autorun file (/home/autorun)
|
||||
|
||||
User autorun files are good if you're not
|
||||
too much of a professional. You can load
|
||||
extra APIs or perform other actions.
|
||||
More about user autorun files can be found
|
||||
at 'man custom-autorun'.
|
||||
|
||||
2. Writing a custom bootloader
|
||||
|
||||
Information about custom bootloaders can
|
||||
be found at 'man custom-bootloaders'
|
11
etc/manuals/custom-bootloaders
Normal file
11
etc/manuals/custom-bootloaders
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
In FREAX, bootloader records are files that
|
||||
regulate the boot order of the operating system,
|
||||
responsible for the low-level system routines.
|
||||
|
||||
Writing a bootloader record requires a lot of
|
||||
experience in Lua programming.
|
||||
|
||||
FREAX's standard bootloader record is located
|
||||
in '/boot/loaders/ofbl-splash'. It is strongly
|
||||
recommended not to touch it.
|
17
etc/manuals/custom-build
Normal file
17
etc/manuals/custom-build
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
You can build your own FREAX distribution,
|
||||
assuming that you have the system requirements:
|
||||
- 1Ridav's Archiver must be present on your
|
||||
system and the receiver's system
|
||||
|
||||
Run these commands in the shell:
|
||||
archiver zip / <name> rom <build directory>
|
||||
mv <name>.arch <build directory>
|
||||
|
||||
To install, run this command:
|
||||
<archiver path> unzip <name>.arch /
|
||||
|
||||
Alternatively, you can download the
|
||||
'freax-buildtools' package and type 'buildtool'
|
||||
in the console - it will automatically build a
|
||||
system image.
|
14
etc/manuals/custom-script
Normal file
14
etc/manuals/custom-script
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
A FREAX script file is actually a bunch of
|
||||
strings representing commands and executables.
|
||||
|
||||
An example script is provided at the path
|
||||
'/system/demos/script.tsf'. Note that the
|
||||
header is VERY necessary, as without it the
|
||||
script parser will not be able to recognize
|
||||
the code.
|
||||
|
||||
Useful commands:
|
||||
@/scomment - comment out strings
|
||||
sdelay <seconds> - delay execution for set time
|
||||
secho [text] - output text/newline to console
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue