Add to Git

This commit is contained in:
Sukasa 2017-02-05 22:54:11 -08:00
commit b7cd1a1234
4 changed files with 488 additions and 0 deletions

141
autorun.lua Normal file
View File

@ -0,0 +1,141 @@
-- Installer / Configurer for DistFS
local io = require("io")
local os = require("os")
local fs = require("filesystem")
local shell = require("shell")
local computer = require("computer")
local folders = {
"/etc/distfs"
}
local files = {
["distfs.boot.lua"] = "/boot/97_distfs.lua",
["distfs.filesystem.lua"] = "/lib/distfs.lua",
["distfs.version"] = "/etc/distfs/distfs.version"
}
function getYesNo(question, defaultYes)
while true do
local yesNo = "? [y/N] "
if defaultYes then yesNo = "? [Y/n] " end
io.write(question..yesNo)
yesNo = io.read():lower()
if yesNo == "y" then return true end
if yesNo == "n" then return false end
if yesNo == "" then return defaultYes end
end
end
local filePath = nil
for mountpoint in fs.list("/mnt") do
if fs.exists("/mnt/" .. mountpoint .. "distfs.version") then
filePath = "/mnt/" .. mountpoint .. "distfs.version"
break
end
end
if filePath == nil then
print("Unable to locate install disk in mount structure")
return
end
local install = false
local freshInstall = not fs.exists("/etc/distfs/distfs.cfg")
local sourcePath = fs.path(filePath)
local versionFile, err = io.open(filePath)
local version = "??"
if versionFile ~= nil then
version = versionFile:read("*n")
versionFile:close()
versionFile = nil
else
io.write("Error opening distfs.version: " .. err .. ". Press enter to continue.")
io.read()
end
os.execute("clear")
io.write("\n")
io.write(" ___ _ __ ______ _____ \n")
io.write(" / __ \\ (_)_____ / /_ / ____// ___/\n")
io.write(" / / / // // ___// __// /_ \\__ \\ \n")
io.write(" / /_/ // /(__ )/ /_ / __/ ___/ / \n")
io.write("/_____//_//____/ \\__//_/ /____/ \n")
io.write("\nDistFS v" .. version .. " for OpenOS by Sukasa\n")
io.write("\n")
if true then
install = getYesNo("Install DistFS", true)
if install then
for _, folder in pairs(folders) do
fs.makeDirectory(folder)
end
for src,dst in pairs(files) do
io.write(src .. " -> " .. dst .. "\n")
local command = "cp " .. sourcePath .. src .. " " .. dst
os.execute(command)
end
end
if not install and freshInstall then
os.execute("clear")
return
end
if install then
io.write("\nInstalled DistFS v" .. version )
io.write("\n")
end
end
-- Now ask about options
local reconfigure = false
local configureMe = fs.exists("/etc/distfs/distfs.cfg")
local configString = "Configure"
if not freshInstall then configString = "Reconfigure" end
if (freshInstall and install) or (configureMe and getYesNo(configString .. " DistFS", true)) then
reconfigure = true
local raidOnly = getYesNo("Ignore local hard drives and disk drives", true)
local allowHotplug = getYesNo("Allow hotplugging of new RAID units", true)
local arrayMaster = getYesNo("System is array master", false)
local bootSync = arrayMaster and getYesNo("Synchronize RAID arrays on boot", false)
local addSync = arrayMaster and getYesNo("Synchronize RAID arrays on volume addition", true)
local configFile = io.open("/etc/distfs/distfs.cfg", "w")
configFile:write("raidOnly=" .. tostring(raidOnly) .."\n")
configFile:write("arrayMaster=" .. tostring(arrayMaster) .."\n")
configFile:write("allowHotplug=" .. tostring(allowHotplug) .."\n")
configFile:write("bootSync=" .. tostring(bootSync) .."\n")
configFile:write("addSync=" .. tostring(addSync) .."\n")
configFile:close()
io.write("Wrote new DistFS configuration\n\n")
end
local reboot = false
if install then
reboot = getYesNo("DistFS has been installed.\n\nReboot now", true)
end
if not install and reconfigure then
reboot = getYesNo("DistFS has been reconfigured.\n\nReboot now", true)
end
if reboot then
computer.shutdown(true)
else
os.execute("clear")
end

43
distfs.boot.lua Normal file
View File

@ -0,0 +1,43 @@
local function DoDistFS()
local dfs = require("distfs")
local fs = require("filesystem")
local io = require("io")
if not fs.exists("/lib/distfs.lua") then
io.stderr:write("DistFS missing! Unable to load DistFS")
return
end
require("filesystem").mount(
require("distfs").proxy
, "/distfs")
local function split(s)
local fields = {}
local pattern = string.format("([^%s]+)", "=")
s:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
end
if not fs.exists("/etc/distfs/distfs.cfg") then
io.stderr:write("DistFS configuration file missing! Reverting to defaults...")
end
local function toBool(s)
return s:lower() == "true"
end
for line in io.lines("/etc/distfs/distfs.cfg") do
local d = split(line)
dfs[d[1]] = toBool(d[2])
end
dfs.init()
end
local success, err = pcall(DoDistFS)
if not success then
--io.stderr:write("Failed to initialize DistFS: " .. err)
end

303
distfs.filesystem.lua Normal file
View File

@ -0,0 +1,303 @@
local event = require("event")
local component = require("component")
local io = require("io")
local os = require("os")
fs = {}
-- Default configuration
fs.raidsOnly = true
fs.allowHotplug = true
fs.arrayMaster = false
fs.bootSync = false
fs.addSync = false
function fs.componentAdded(eventId, componentPath, componentType)
if componentType == "filesystem" then
for i = 1, #fs.filesystems do
if fs.filesystems[i].address == componentPath then
return -- Don't re-add filesystems if they're already in.
end
end
local sys = component.proxy(componentPath)
if (not fs.raidsOnly) or sys.getLabel() == "raid" then
table.insert(fs.filesystems, sys)
if eventId == "component_added" and fs.arrayMaster and fs.addSync then
fs.syncFilesystems()
end
if eventId == "init" then
--io.write("> .. Mounted FS " .. componentPath .. "\n")
end
end
end
end
function fs.syncFilesystems()
if not fs.arrayMaster then return false, "Not array master" end
local folderList = { "/" }
-- Build a list of all folders on all drives
for i = 1,#folderList do
local path = folderList[i]
local search = {}
for _,system in pairs(fs.filesystems) do
local sysFiles = system.list(path)
for _,file in ipairs(sysFiles) do
local filePath = path..file
if system.isDirectory(filePath) then
if not fs.contains(search, filePath) then
table.insert(search, filePath)
table.insert(folderList, filePath)
end
end
end
--os.sleep(0.05)
end
end
-- Ensure each of these folders exists on every drive
for _, folder in ipairs(folderList) do
for _, system in ipairs(fs.filesystems) do
system.makeDirectory(folder)
end
--os.sleep(0.05)
end
return true
end
function fs.init()
fs.handles = {}
fs.filesystems = {}
--io.write("> . Performing DistFS initialization...\n")
for k,_ in pairs(component.list("filesystem")) do
fs.componentAdded("init", k, "filesystem")
end
if fs.allowHotplug then event.listen("component_added", fs.componentAdded) end
if fs.bootSync and fs.arrayMaster then
--io.write("> . Performing DistFS synchronization...\n")
fs.syncFilesystems()
end
--io.write("> . DistFS ready! Spanning " .. #fs.filesystems .. " volumes.\n")
end
function fs.contains(haystack, needle)
for i=1,#haystack do
if haystack[i] == needle then return true end
end
return false
end
function fs.merge(outTable, table2)
for src = 1, #table2 do
if not fs.contains(outTable, table2[src]) then table.insert(outTable, table2[src]) end
end
end
function fs.mostFreeSpace()
-- Return whichever FS has the most free space available
local avail = 0
local sys = nil
for _,system in pairs(fs.filesystems) do
local a = system.spaceTotal() - system.spaceUsed()
if a > avail then
avail = a
sys = system
end
end
return sys
end
function fs.findFile(path)
-- Search through filesystems until I find the file we're looking for and return the filesystem containing it
for _, sys in pairs(fs.filesystems) do
if sys.exists(path) then return sys end
end
return nil
end
-- Proxy Objects for FS Component --
fs.proxy = {}
fs.proxy.address = "62645f02-a97d-4e3a-8c1d-7f88f4dacbc2"
function fs.proxy.spaceUsed()
local used = 0
for _,system in pairs(fs.filesystems) do
used = used + system.spaceUsed()
end
return used
end
function fs.proxy.open(path, mode)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
-- Either open the file on its existing filesystem, create it on the FS with the most free space, or fail if we're trying to open something non-existent for reading
checkArg(1, path, "string")
checkArg(2, mode, "string", "nil")
mode = mode or "r"
local bRead = mode:match("[ra]")
local bWrite = mode:match("[wa]")
if not bRead and not bWrite then
return nil, "invalid mode"
end
local system = fs.findFile(path)
local handle, err
if system ~= nil then
handle, err = system.open(path, mode)
else
if bRead then
return nil, path
end
system = fs.mostFreeSpace()
handle, err = system.open(path, mode)
end
-- Associate the file handle with the FS in fs.handles
if handle ~= nil then
fs.handles[handle] = system
end
return handle, err
end
function fs.proxy.seek(handle, whence, offset)
if fs.handles[handle] == nil then
return false, "unknown file handle"
end
fs.handles[handle].seek(handle, whence, offset)
end
function fs.proxy.makeDirectory(path)
if #fs.filesystems == 0 then return false, "No spanned volumes" end
local okay = true
for _,system in pairs(fs.filesystems) do
okay = okay and ((not system.exists(path)) or system.isDirectory(path))
end
if not okay then return false end
for _,system in pairs(fs.filesystems) do
okay = okay and (system.isDirectory(path) or system.makeDirectory(path))
end
return okay
end
function fs.proxy.exists(path)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
for _,system in pairs(fs.filesystems) do
if system.exists(path) then return true end
end
return false
end
function fs.proxy.isReadOnly()
return false
end
function fs.proxy.write(handle, value)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
if fs.handles[handle] == nil then
return false, "unknown file handle"
end
return fs.handles[handle].write(handle, value)
end
function fs.proxy.spaceTotal()
local total = 0
for _,system in pairs(fs.filesystems) do
total = total + system.spaceTotal()
end
return total
end
function fs.proxy.isDirectory(path)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
return fs.filesystems[1].isDirectory(path) -- this relies on the filesystems being in sync
end
function fs.proxy.rename(from, to)
if fs.proxy.exists(to) then
return false, "target file already exists"
else
local srcsys = fs.findFile(from)
if srcsys == nil then return false, "source file doesn't exist" end
return srcsys.rename(from, to)
end
end
function fs.proxy.list(path)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
local list = {}
-- Get a list of all files from every fs for this folder and return it
for _, sys in pairs(fs.filesystems) do
local add = sys.list(path)
if add ~= nil then
fs.merge(list, sys.list(path))
end
end
if #list == 0 then return nil end
return list
end
function fs.proxy.lastModified(path)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
local sys = fs.findFile(path)
if sys == nil then return nil, "file doesn't exist" end
return sys.lastModified(path)
end
function fs.proxy.getLabel()
return "DistFS"
end
function fs.proxy.remove(path)
if #fs.filesystems == 0 then return false, "No spanned volumes" end
local sys = fs.findFile(path)
if sys == nil then return false, "file doesn't exist" end
return sys.remove(path)
end
function fs.proxy.close(handle)
if fs.handles[handle] == nil then
return false, "unknown file handle"
end
local a, b = fs.handles[handle].close(handle)
if a then fs.handles[handle] = nil end
return a, b
end
function fs.proxy.size(path)
if #fs.filesystems == 0 then return nil, "No spanned volumes" end
local sys = fs.findFile(path)
if sys == nil then return nil, "file doesn't exist" end
return sys.size(path)
end
function fs.proxy.read(handle, count)
if fs.handles[handle] == nil then
return false, "unknown file handle"
end
return fs.handles[handle].read(handle, count)
end
function fs.proxy.setLabel(newLabel)
return fs.proxy.getLabel() -- No.
end
-- Extra utility functions
function fs.proxy.sync()
fs.syncFilesystems()
end
return fs

1
distfs.version Normal file
View File

@ -0,0 +1 @@
1.3