Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- os.pullEvent = os.pullEventRaw
- local version = "v.1.1"
- local bootable_tag = "-- CRAFTLOADER BOOTABLE MEDIA"
- local nOption = 1
- local bootCfg = {}
- local timer;
- local w, h = term.getSize()
- local function halt()
- while true do
- sleep(1)
- end
- end
- local function print_centered(y, str)
- term.setCursorPos(math.floor((w - string.len(str)) / 2), y)
- term.clearLine()
- write(str)
- end
- local function split(inputstr, sep)
- if sep == nil then
- sep = "%s"
- end
- local t = {}
- for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
- table.insert(t, str)
- end
- return t
- end
- --[[ This is a copy of libs from /lib folder
- in case it is missing there. I just don't want to
- add dependencies to bootloader
- ]]
- --[[ CONFIG ]]
- local function save(tbl, name)
- local file = fs.open(name, "w")
- file.write(textutils.serialize(tbl))
- file.close()
- end
- local function createIfNotExists(name)
- if not fs.exists(name) then
- local file = fs.open(name, "w")
- file.close()
- return true
- end
- return false
- end
- local function load(name)
- local file = fs.open(name, "r")
- local tbl = textutils.unserialize(file.readAll())
- file.close()
- return tbl
- end
- local function print_err(exception)
- -- save old color formatting
- local bg = term.getBackgroundColor()
- local fg = term.getTextColor()
- -- set colors
- term.setBackgroundColor(colors.gray)
- term.setTextColor(colors.red)
- -- print error
- print(exception)
- -- restore colors
- term.setBackgroundColor(bg)
- term.setTextColor(fg)
- end
- --[[ ARGS PARSER ]]
- local parser = {}
- function parser:new()
- local obj = {
- flags = {},
- options = {},
- parsed = {flags = {}, options = {}, args = {}}
- }
- self.__index = self
- return setmetatable(obj, self)
- end
- function parser:addFlag(canonical, ...)
- local variants = {...}
- self.flags[canonical] = {false, variants}
- for _, variant in ipairs(variants) do
- self.flags[variant] = {false, {canonical}}
- end
- end
- function parser:addOption(canonical, ...)
- local variants = {...}
- self.options[canonical] = {nil, variants}
- for _, variant in ipairs(variants) do
- self.options[variant] = {nil, {canonical}}
- end
- end
- function parser:parse(args)
- local i = 1
- while i <= #args do
- local arg = args[i]
- if self.flags[arg] then
- for _, variant in ipairs(self.flags[arg][2]) do
- self.parsed.flags[variant] = true
- end
- self.parsed.flags[arg] = true
- elseif self.options[arg] then
- if i + 1 <= #args then
- local value = args[i + 1]
- for _, variant in ipairs(self.options[arg][2]) do
- self.parsed.options[variant] = value
- end
- self.parsed.options[arg] = value
- i = i + 1
- else
- error("Option " .. arg .. " expects a value")
- end
- else
- table.insert(self.parsed.args, arg)
- end
- i = i + 1
- end
- end
- function parser:getFlags()
- local result = {}
- for flag, _ in pairs(self.flags) do
- if self.parsed.flags[flag] then
- result[flag] = true
- end
- end
- return result
- end
- function parser:getOptions()
- local result = {}
- for option, _ in pairs(self.options) do
- if self.parsed.options[option] then
- result[option] = self.parsed.options[option]
- end
- end
- return result
- end
- function parser:getArgs()
- return self.parsed.args
- end
- --[[
- End of libs copies
- ]]
- --[[
- CLI
- ]]
- function string.starts(str, str1)
- return str:sub(1, #str1) == str1
- end
- function handleCommand(command, arguments)
- args = parser:new()
- if command:lower() == "shutdown" then
- os.shutdown()
- elseif command:lower() == "reboot" then
- os.reboot()
- elseif command:lower() == "boot" then -- boot command
- args:addOption("--entry", "-e")
- args:addFlag("--help", "-h")
- args:parse(arguments)
- local flags = args:getFlags()
- local options = args:getOptions()
- local boot_args = args:getArgs()
- if flags["--help"] then
- print("usage: boot --entry | -e path/to/entry")
- print("Boots from specified path if entry exists")
- return
- end
- if options["--entry"] then
- if not fs.exists(options["--entry"]) then
- print_err("Error: Path does not exists")
- return
- end
- local path = options["--entry"]
- local handle = fs.open(path, "r")
- if not handle then
- print_err("Error: Cannot open the Path")
- return
- end
- local tag = handle.read(#bootable_tag)
- if not tag == bootable_tag then
- print_err("Error: Path is not valid bootable media!")
- return
- end
- term.clear()
- term.setCursorPos(0,0)
- shell.setDir(fs.getDir(path))
- shell.run(path, table.concat(boot_args, " "))
- else
- print("usage: boot --entry | -e path/to/entry")
- end
- elseif command:lower() == "chkmedia" then
- args:addOption("--media", "-m")
- args:parse(arguments)
- local options = args:getOptions()
- if not fs.exists(options["--media"]) then
- print_err("Error: Path does not exists")
- return
- end
- local handle = fs.open(options["--media"], "r")
- if not handle then
- print_err("Error: Cannot open Path")
- return
- end
- local tag = handle.read(#bootable_tag)
- print(tag == bootable_tag)
- elseif command:lower() == "help" then
- print("Allowed commands: shutdown reboot boot halt help chkmedia")
- elseif command:lower() == "halt" then
- halt()
- else
- print("Allowed commands: shutdown reboot boot halt help chkmedia")
- end
- end
- function runCLI()
- while true do
- -- read input
- write("> ")
- local input = read()
- local sp = split(input, ' ')
- local arguments = table.remove(sp, 1)
- handleCommand(sp[1], arguments)
- end
- end
- --[[
- BOOTLOADER
- ]]
- local function drawEntrySelector()
- term.clear()
- term.setCursorPos(0,0)
- print_centered(1, "CBL "..version .. "\n")
- for i = 1, w do
- write("=")
- end
- term.setCursorPos(1,3)
- for i, v in ipairs(bootCfg.options) do
- if nOption == i then
- term.setBackgroundColor(colors.lightGray)
- term.setTextColor(colors.black)
- term.clearLine()
- print(" > " .. v.name)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- else
- print(" " .. v.name)
- end
- end
- for i = 1, w do
- write("=")
- end
- write("\n")
- print("Use arrows to select and enter to boot")
- end
- local function handleTimer()
- while true do
- local event = os.pullEvent("timer")
- if event == "timer" then
- break
- end
- end
- end
- local function handleInput()
- while true do
- local event, key = os.pullEvent("key")
- if event == "key" then
- if keys.getName(key) == "up" then
- os.cancelTimer(timer)
- if nOption > 1 then
- nOption = nOption - 1
- end
- elseif keys.getName(key) == "down" then
- os.cancelTimer(timer)
- if nOption < #bootCfg.options then
- nOption = nOption + 1
- end
- elseif keys.getName(key) == "enter" then
- os.cancelTimer(timer)
- break
- end
- term.clear()
- drawEntrySelector()
- end
- end
- end
- if createIfNotExists("/etc/craftbl/boot.cfg") then
- bootCfg = {
- timeout = 3,
- default_option = 1,
- options = {
- [1] = {
- name = "DiamondOS",
- path = "/boot/boot.lua",
- args = {},
- },
- [2] = {
- name = "CraftBootloader CLI",
- path = "craft://cli",
- args = {},
- },
- },
- }
- save(bootCfg, "/etc/craftbl/boot.cfg")
- end
- -- preload
- bootCfg = load("/etc/craftbl/boot.cfg")
- if bootCfg == nil then
- print_err("No boot configuration found!")
- runCLI()
- elseif bootCfg.options == nil then
- print_err("No boot options found!")
- runCLI()
- elseif bootCfg.default_option == nil then
- bootCfg.default_option = 1
- end
- if #bootCfg.options > 1 then
- -- menu (if more than one entry)
- nOption = bootCfg.default_option
- drawEntrySelector()
- print("Botting in " .. bootCfg.timeout .. " sec")
- timer = os.startTimer(bootCfg.timeout)
- parallel.waitForAny(handleInput, handleTimer)
- term.clear()
- term.setCursorPos(1,1)
- if bootCfg.options[nOption].path == "craft://cli" then
- os.cancelTimer(timer)
- runCLI()
- end
- local handle = fs.open(bootCfg.options[nOption].path, "r") -- look for boot pattern on first line ("-- CRAFTBOOT BOOTABLE MEDIA")
- if not handle then
- print_err("Unable to read boot path")
- os.cancelTimer(timer)
- runCLI()
- end
- local entry = handle.read(#bootable_tag)
- if entry ~= bootable_tag then
- print_err(bootCfg.options[nOption].path .. " is not bootable media!")
- os.cancelTimer(timer)
- runCLI()
- end
- shell.setDir(fs.getDir(bootCfg.options[nOption].path))
- shell.run(bootCfg.options[nOption].path, table.concat(bootCfg.options[nOption].args, " "))
- else
- term.clear()
- term.setCursorPos(1,1)
- if bootCfg.options[1].path == "craft://cli" then
- runCLI()
- end
- local handle = fs.open(bootCfg.options[1].path, "r") -- look for boot pattern on first line ("-- CRAFTBOOT BOOTABLE MEDIA")
- local entry = handle.read(#bootable_tag)
- if entry ~= bootable_tag then
- print_err(bootCfg.options[1] .. " is not bootable media!")
- runCLI()
- end
- shell.setDir(fs.getDir(bootCfg.options[1].path))
- shell.run(bootCfg.options[1].path, table.concat(bootCfg.options[1].args, " "))
- end
Advertisement
Add Comment
Please, Sign In to add comment