module (..., package.seeall) -- Load libraries require("fs") require("format") require("getopts") require("daemoncontrol") -- Set variables local configfile = "/etc/lbu/lbu.conf" -- ################################################################################ -- LOCAL FUNCTIONS local function get_version () local f,error = io.popen("/sbin/lbu 2>&1") local programversion = f:read("*l") f:close() return programversion end local function getLbuStatus() local ret = {} local f = io.popen("/sbin/lbu status -v 2>&1", "r") if not (f) then return ret end for line in f:lines() do if (string.match(line, "^Include files")) then break end if (string.match(line, "^Exclude files")) then break end local status, name = string.match(line, "^(%S+)%s+(.+)$") if (status) and (name) then ret[string.gsub('/' .. name, "/+", "/")] = status end end f:close() return ret end local function availablemedias() return {"floppy","usb"} end local function getLbuCommit(flag) local err = {} local ret = "" local f = io.popen("/sbin/lbu commit " .. flag .. " 2>&1", "r") for line in f:lines() do ret = ret .. line .. "\n" --Look for error messages in output local searchrow, search = string.match(line, "^(lbu.*(%-%a).*)") if (search) then err[search] = searchrow end end f:close() return ret, err end local function getciphers() local opensslciphers = {} local watchdog = nil local f = io.popen("/usr/bin/openssl -v 2>&1", "r") if not (f) then return ciphers end for line in f:lines() do if (watchdog) then for cipher in string.gmatch(line, "(%S+)") do table.insert(opensslciphers,tostring(cipher)) end end if (string.match(line, "^Cipher commands")) then watchdog="yes" end end f:close() return opensslciphers end local function getincexl(state) local incexl = {} if (string.lower(state) == "include") or (string.lower(state) == "exclude") then local f = io.popen("/sbin/lbu " .. string.lower(state) .. " -l 2>&1", "r") if not (f) then return incexl end for line in f:lines() do table.insert(incexl,tostring(line)) end f:close() end return incexl end -- ################################################################################ -- PUBLIC FUNCTIONS function getstatus () local path = configfile local status = {} local statustxt local descrtxt if (#list() == 0) then statustxt = "There is no uncommited files" else statustxt = "WARNING!" descrtxt = "Until you commit, you will lose your changes at next reboot/shutdown!" end local config = getconfig() status["version"] = cfe({ name="status", value=get_version(), label="Program version", }) status["status"] = cfe({ name="status", value=statustxt, descr=descrtxt, label="Program status", }) status["LBU_MEDIA"] = config["LBU_MEDIA"] if (config["ENCRYPTION"]["checked"]) then status["ENCRYPTION"] = config["ENCRYPTION"] status["ENCRYPTION"]["descr"] = "Using cipher '".. config.DEFAULT_CIPHER.value .. "' for encryption" end return status end function list(self) local ret = {} local lbuStatus = getLbuStatus() for k,v in pairs(lbuStatus) do ret[#ret + 1] = { name=k, status=v } end table.sort(ret, function(a,b) return (a.name < b.name) end) return ret end function getcommit(self, flag) --See to that only allowed flags are passed to the process flag = string.match(flag or "", "%-%a") or "" return getLbuCommit("-v " .. flag) end function getsimulate(self, flag) --See to that only allowed flags are passed to the process flag = string.match(flag or "", "%-%a") or "" return getLbuCommit("-n " .. flag) end function getconfig () local path = configfile local config = {} local configopts local errors = {} if (fs.is_file(path)) then configopts = getopts.getoptsfromfile_onperline(path) or {} end local lbumedias = availablemedias() if not (configopts.LBU_MEDIA) then local lbumessage = "No default" table.insert(lbumedias, lbumessage) config.LBU_MEDIA = lbumessage else config.LBU_MEDIA = configopts.LBU_MEDIA end config["debug"] = configopts config["LBU_MEDIA"] = cfe({ name="LBU_MEDIA", value=config["LBU_MEDIA"], label="Default media for commit", type="select", option=lbumedias, }) config["lbu_included"]= cfe({ name="lbu_included", option=getincexl("include") or {}, label="Included item(s)", type="select", size=table.maxn(getincexl("include"))+1, }) if (config["lbu_included"]["size"] == 1) then config["lbu_included"]["size"] = 2 end config["lbu_excluded"]= cfe({ name="lbu_excluded", option=getincexl("exclude") or {}, label="Excluded item(s)", type="select", size=table.maxn(getincexl("exclude"))+1, }) if (config["lbu_excluded"]["size"] == 1) then config["lbu_excluded"]["size"] = 2 end config["ENCRYPTION"] = cfe({ name="ENCRYPTION", value="yes", label="Password protected commits", type="checkbox", }) if (configopts["ENCRYPTION"]) and (#configopts["ENCRYPTION"] ~= 0) then config["ENCRYPTION"]["checked"] = "yes" end config["DEFAULT_CIPHER"] = cfe({ name="DEFAULT_CIPHER", value=configopts["DEFAULT_CIPHER"], label="Cipher to use at encryption", option=getciphers() or {}, type="select", }) config["PASSWORD"] = cfe({ name="PASSWORD", value=configopts["PASSWORD"], label="Password when encrypting", }) -- Next section is to print errormessages when configs are wrong if (configopts["LBU_MEDIA"] == "") or (configopts["LBU_MEDIA"] == nil) then config.LBU_MEDIA.errtxt = "'Media' needs to be configured!" end if (configopts["PASSWORD"] == nil) and (configopts["ENCRYPTION"] ~= nil) then config.PASSWORD.errtxt = "Encryption without password is not allowed!
Deactivate 'Password protection' or configure a password!" end for k,v in pairs(errors) do config["errors"] = v end return config end function lbuincexcl(self,state,value,addremove) local incexl = nil if (string.lower(addremove or "") == "add") then addremove = "" elseif (string.lower(addremove or "") == "remove") then addremove = "-r" else return "Function setincexl() - Invalid option! Use add|remove when calling this function!" end if (string.lower(state) == "include") or (string.lower(state) == "exclude") then local f = io.popen("/sbin/lbu " .. string.lower(state) .. " " .. addremove .. " -v " .. value .." 2>&1", "r") if not (f) then return incexl end incexl = f:read("*a") f:close() else return "Function setincexl() - Invalid command! Use included|excluded when calling this function!" end return incexl end function editconfig (self,variable,value) local configfilecontent = nil local path = configfile local cmdoutput = nil if not (fs.is_file(path)) then fs.write_file(path,"") end local deactivate = "" if not (value) or (value == "") then deactivate = "#" end if (variable == "LBU_MEDIA") then local errtxt local lbumedias = availablemedias() for k,v in pairs(lbumedias) do errtxt = "" if (value == v) then break end errtxt = "Not a valid media!" end if (#errtxt > 0) then return errtxt end end -- Hardcode some parameters (e.g for some checkboxes) if (variable == "ENCRYPTION") then value = "DEFAULT_CIPHER" end configfilecontent = fs.read_file_as_array(path) or {} -- Search if the variable is defined in the file for k,v in pairs(configfilecontent) do if (string.match(v,"^%s*%#*%s*" .. variable)) then cmdoutput = format.search_replace(configfilecontent,"^%s*%#*%s*" .. variable .. ".*$", deactivate .. variable .. "=" .. value) break end end --If variable is not changed (didn't exist) then create a new row with this variable if not (cmdoutput) then cmdoutput = configfilecontent table.insert(cmdoutput,deactivate .. variable .. "=" .. (value or "")) end -- Write changes to file fs.write_file(path,table.concat(cmdoutput,"\n")) return value end function get_filedetails() local path = configfile local file = {} local filedetails = {} local config = {} local filenameerrtxt if (fs.is_file(path)) then filedetails = fs.stat(path) config = getconfig(path) else config = {} config.filename = {} config["filename"]["errtxt"]="Config file '".. path .. "' is missing!" end file["filename"] = cfe({ name="filename", label="File name", value=path, errtxt=filenameerrtxt }) file["filesize"] = cfe({ name="filesize", label="File size", value=filedetails.size or 0, }) file["mtime"] = cfe({ name="mtime", label="File date", value=filedetails.mtime or "---", }) file["filecontent"] = cfe({ type="longtext", name="filecontent", label="File content", value=fs.read_file(path), }) -- Sum all errors into one cfe local sumerrors = "" for k,v in pairs(config) do if (config[k]) and (config[k]["errtxt"]) and (config[k]["errtxt"] ~= "") then sumerrors = sumerrors .. config[k]["errtxt"] .. "\n" end end if (sumerrors ~= "") then file["sumerrors"] = cfe ({ name="sumerrors", label = "Configuration errors", errtxt = string.match(sumerrors, "(.-)\n$"), }) end return file end function update_filecontent (self, modifications) local path = configfile local file_result,err = fs.write_file(path, format.dostounix(modifications)) return file_result, err end