Initial commit

This commit is contained in:
JeremyStarTM 2022-07-18 19:33:40 +02:00
commit e9e68d9f28
175 changed files with 10337 additions and 0 deletions

5
README.md Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
shell.run("/bin/man credits")

2
bin/detach Normal file
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,5 @@
if security.getSU() then
shell.exit()
else
kernel.reboot(true)
end

1
bin/firststeps Normal file
View file

@ -0,0 +1 @@
shell.run("/bin/man firststeps")

994
bin/gclone Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
shell.run("/bin/nano /etc/manuals")

18
bin/mkdir Normal file
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,4 @@
-- testing
net.openModems()
net.setWorkstationStatus(true)
print(tostring(net.getWorkstationStatus()))

50
bin/nmap Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,6 @@
{
[ "enableBootScreen" ] = "true",
[ "doSystemSetup" ] = "true",
[ "logo" ] = "/boot/freax/freax.img",
[ "logo_small" ] = "/boot/freax/freax-small.img",
}

View file

@ -0,0 +1,7 @@
aaaaaaaaaaaaaaaaaaa
aaa000aaaeeaaeeaaaa
aaa0aaaaaaa11aaaaaa
aaa000aaaaa44aaaaaa
aaa0aaaaaaa55aaaaaa
aaa0aaaaa33aa33aaaa
aaaaaaaaaaaaaaaaaaa

7
boot/freax/freax.img Normal file
View file

@ -0,0 +1,7 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaa000aaa0000aaa000aaa0000aaaeeaaeeaa
aaa0aaaaa0aa0aaa0aaaaa0aa0aaaaa11aaaa
aaa000aaa0000aaa000aaa0000aaaaa44aaaa
aaa0aaaaa00aaaaa0aaaaa0aa0aaaaa55aaaa
aaa0aaaaa0a00aaa000aaa0aa0aaa33aa33aa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

169
boot/freax/initrd.img Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,2 @@
207d:19:39 | Cannot serialize type function
208d:6:38 | 1

22
etc/lib/config Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,7 @@
Some manuals belong to categories.
Here they are:
api - FREAX APIs
custom - customization

15
etc/manuals/changelog Normal file
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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'

View 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
View 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
View 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