Add to Git
This commit is contained in:
commit
b7cd1a1234
141
autorun.lua
Normal file
141
autorun.lua
Normal 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
43
distfs.boot.lua
Normal 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
303
distfs.filesystem.lua
Normal 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
1
distfs.version
Normal file
@ -0,0 +1 @@
|
||||
1.3
|
Loading…
Reference in New Issue
Block a user