module(..., package.seeall) require("modelfunctions") require("fs") require("getopts") require("format") require("validator") local configfile = "/etc/conf.d/syslog" local processinitname = "syslog" local processname = "syslogd" local function get_version() local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin apk_version -v -s busybox | cut -d ' ' -f 1" local cmd_output = io.popen( cmd ) local cmd_output_result = cmd_output:read("*a") or "" cmd_output:close() return cmd_output_result end local function getloglevels() local loglevels = {} for i=1,8 do table.insert(loglevels,tostring(i)) end return loglevels end local writeconfig = function (config) -- Set variables local variable = "SYSLOGD_OPTS" local variabletranslator = { logfile = "-O", loglevel = "-l", smallerlogs = "-S", maxsize = "-s", numrotate = "-b", localandnetworklog = "-L", remotelogging = "-R", } local configdata = {} for name, entry in pairs(variabletranslator) do if config.value[name] and config.value[name].type == "boolean" then if config.value[name].value then configdata[entry] = "" end elseif config.value[name] and config.value[name].value and #config.value[name].value > 0 then configdata[entry] = config.value[name].value else configdata[entry] = nil end end local cmdresult, cmdmessage, cmderror = getopts.setoptsinfile(configfile,"",variable,'"' .. getopts.table_to_opts(configdata) .. '"') return cmdmessage, cmderror end local makeconfig = function(configcontent) local config = {} configcontent = configcontent or {} -- Next section selects which configurations we should show to the user config["logfile"] = cfe({ label = "Log to given file", descr = "File must be in /var/log directory", value = configcontent["-O"] or "/var/log/messages", }) config["loglevel"] = cfe({ label = "Set local log level", value = configcontent["-l"] or "8", type = "select", option = getloglevels(), descr = "1=Quiet, ... , " .. table.maxn(getloglevels()) .. "=Debug", }) config["smallerlogs"] = cfe({ label = "Smaller logging output", value = (configcontent["-S"] == ""), type = "boolean", }) config["maxsize"] = cfe ({ label = "Max size (KB) before rotate", descr = "Default=200KB, 0=off", value = configcontent["-s"] or "", }) config["numrotate"] = cfe ({ label = "Number of rotated logs to keep", descr = "Default=1, max=99, 0=purge", value = configcontent["-b"] or "", }) config["localandnetworklog"] = cfe ({ label = "Log locally and via network", value = (configcontent["-L"] == ""), type = "boolean", descr = "Default is network only if host[:PORT] is defined", }) config["remotelogging"] = cfe ({ label = "Log to IP or hostname on PORT", descr = "host[:PORT] - Default PORT=514/UDP", value = configcontent["-R"] or "", }) return cfe({ type="group", value=config, label="Configuration" }) end local validateconfig = function(config) local success = true -- Validate entries and create error strings if not validator.is_valid_filename(config.value.logfile.value, "/var/log") then config.value.logfile.errtxt = "Not a valid file name in /var/log" success = false end if not validator.is_integer_in_range(config.value.loglevel.value, 1, 8) then config.value.loglevel.errtxt = "Out of range!" success = false end if config.value.maxsize.value ~= "" and not validator.is_integer(config.value.maxsize.value) then config.value.maxsize.errtxt = "Must be an integer" success = false end if config.value.numrotate.value ~= "" and not validator.is_integer_in_range(config.value.numrotate.value, 0, 99) then config.value.numrotate.errtxt = "Out of range!" success = false end if config.value.localandnetworklog.value == true and config.value.remotelogging.value == "" then config.value.localandnetworklog.errtxt = "Logging to local and network is not possible unless you define a host for remote logging" success = false end local hostport = format.string_to_table(config.value.remotelogging.value, ":") if hostport[2] and not (validator.is_port(hostport[2])) then config.value.remotelogging.errtxt = "Not a valid port" success = false end return success, config end -- ################################################################################ -- PUBLIC FUNCTIONS function startstop_service(action) return modelfunctions.startstop_service(processinitname, action) end function getversion() return cfe({ label="Program version", value=get_version(), }) end function getstatus() return modelfunctions.getenabled(processname) end function getlogging() local status = {} local opts = getconfig() if (opts.value.remotelogging.value == "") or (opts.value.localandnetworklog.value) then status.logfile = cfe({ label="Locally logging to", value=opts.value.logfile.value, }) end if (opts.value.remotelogging.value ~= "") then status.remote = cfe({ label="Remote logging to", value=opts.value.remotelogging.value, }) end return cfe({ type="group", value=status }) end function get_filedetails() return modelfunctions.getfiledetails(configfile) end function getconfig() local config = {} if (fs.is_file(configfile)) then local configcontent = getopts.getoptsfromfile(configfile, "", "SYSLOGD_OPTS", true) or {} config = makeconfig(configcontent) else config = makeconfig() config["errtxt"] = "Config file '".. configfile .. "' is missing!" end return config end function updateconfig (config) local success = true success, config = validateconfig(config) if success == true then config.descr, config.errtxt = writeconfig(config) else config.errtxt = "Failed to save config!" end return config end function update_filedetails (filedetails) -- Validation before writing filedetails.value.filecontent.value = string.gsub(format.dostounix(filedetails.value.filecontent.value), "\n+$", "") local configcontent = getopts.getoptsfromfile(filedetails.value.filecontent.value, "", "SYSLOGD_OPTS", true) or {} local config = makeconfig(configcontent) local success, errtxt success, config = validateconfig(config) if success == true then fs.write_file(configfile, filedetails.value.filecontent.value) filedetails = get_filedetails() else local errormessages = {} for x,y in pairs(config.value) do if y.errtxt then errormessages[#errormessages + 1] = y.label .. " - " .. y.errtxt end end filedetails.value.filecontent.errtxt = table.concat(errormessages, "\n") filedetials.errtxt = "Failed to set configuration" end return filedetails end