module(..., package.seeall) require("procps") require("getopts") require("fs") require("format") local configdir local datafile local configfiles = {} local configitems = {} local processname = "tinydns" local configfile = "/etc/conf.d/" .. processname local initdoptions = getopts.getoptsfromfile_onperline("/etc/init.d/" .. processname) if (initdoptions) then configdir = initdoptions.DATADIR datafile = initdoptions.ROOT .. "/data" or "/var/cache/data" else configdir = "/etc/" .. processname datafile = "/var/cache/data" end -- ################################################################################ -- LOCAL FUNCTIONS local function get_version() local cmd_output_result, cmd_output_error local cmd = "/sbin/apk_version -vs " .. processname .." 2>/dev/null" local f = io.popen( cmd ) local cmdresult = f:read("*l") if (cmdresult) and (#cmdresult > 0) then cmd_output_result = string.match(cmdresult,"^%S*") or "Unknown" else cmd_output_error = "Program not installed" end f:close() return cmd_output_result,cmd_output_error end -- This function could be used to check that valid parameters are used in different places local function check_signs(sign) local output = {} local output = {prefix={ ['.']="Name server for your domain", ['&']="Name server", ['=']="Host", ['+']="Alias", ['@']="Mail exchanger", ['=']="Host", ['^']="PTR record", ['C']="Canonical Name", ['Z']="SOA record", [':']="Generic record", ['%']="Client location", }} output = output[sign] return output end -- Return a table with the config-content of a file -- Commented/Blank lines are ignored local function get_value_from_file(file) local output = {} local filecontent = fs.read_file_as_array(file) for i=1,table.maxn(filecontent) do local l = filecontent[i] if not (string.find ( l, "^[;#].*" )) and not (string.find (l, "^%s*$")) then table.insert(output, string.match(l,"(.-)%s*$")) end end if (#output > 0) then return true, output else return false, output end end -- Function to recursively inserts all filenames in a dir into an array local function recursedir(path, filearray) local k,v for k,v in pairs(posix.dir(path) or {}) do -- Ignore files that begins with a '.' if not string.match(v, "^%.") then local f = path .. "/" .. v -- If subfolder exists, list files in this subfolder if (posix.stat(f).type == "directory") then recursedir(f, filearray) else table.insert(filearray, f) end end end end -- Functin to split items into a table local function split_config_items(orgitem) local delimiter = ":" local output = {} output = format.string_to_table(string.sub(orgitem,1,1) .. ":" .. string.sub(orgitem,2),delimiter) output.type = check_signs("prefix") output.type = output.type[string.sub(orgitem,1,1)] or "unknown" -- for k,v in pairs(cnffile) do -- local configcontent = get_value_from_file(v) -- if (configcontent) then -- table.insert(configfiles, v) -- end -- end return output end -- Feed the configfiles table with list of all availage configfiles local function searchforconfigfiles() local cnffile = {} recursedir(configdir, cnffile) for k,v in pairs(cnffile) do local configcontent = get_value_from_file(v) if (configcontent) then table.insert(configfiles, v) end end -- Debug option (adds the sampleconfig content) table.insert(configfiles, "/usr/share/acf/app/tinydns/sampleconfig.conf") end searchforconfigfiles() local function recurseoutput(table,cnt) if not (cnt) then cnt=0 end cnt = cnt + 1 for k,v in pairs(table or {}) do if (type(v) == "string") then io.write(" ".. tostring(v) .. "
") else io.write(" ".. tostring(k) .. "
") recurseoutput(v,cnt) end end end -- Create table with doman levels local function recursedomains(t,array,maxn,currnum) if not (currnum) then currnum = maxn + 1 end currnum = currnum - 1 -- FIXME: The current level should hold information on previous level too! if not (currnum == 0) then if not (array[t[currnum]]) then array[t[currnum]] = {} end recursedomains(t,array[t[currnum]],maxn,currnum) end -- FIXME: This is a /really uggly/ hack to return the current table -- If it's fixed nicely... it would be wonderful! if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]][t[maxn-5]]) then return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]][t[maxn-5]] end if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]]) then return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]] end if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) then return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]] end if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) then return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]] end if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) and (array[t[maxn]][t[maxn-1]][t[maxn-2]]) then return array[t[maxn]][t[maxn-1]][t[maxn-2]] end if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) then return array[t[maxn]][t[maxn-1]] end if (array[t[maxn]]) then return array[t[maxn]] end end -- ################################################################################ -- PUBLIC FUNCTIONS -- Present some general status function getstatus() local status = {} local version,versionerrtxt = get_version() local config = getconfig() status.version = cfe({ name = "version", label="Program version", value=version, errtxt=versionerrtxt, }) status.status = cfe({ name="status", label="Program status", value=procps.pidof(processname), }) status.locations = config.locations status.domains = config.domains return status end -- Return config-information function getconfig() local config = {} local configobjects = {} local locations = {} local domains = {} local debug local version,versionerrtxt = get_version() local listenaddr = getopts.getoptsfromfile_onperline(configfile,"IP") or {} config.listen = cfe({ name = "listen", label="IP address to listen on", value=listenaddr.IP or "", }) --Loop through all available configfiles for k,v in pairs(configfiles) do local filecontent, fileresult fileresult, filecontent = get_value_from_file(v) for kk,vv in pairs(filecontent) do local domaindetails = {} local filecontent_table = split_config_items(vv) -- This is mostly for debugging -- This table contains all available configs table.insert(configobjects, cfe({ name=vv, value=vv, option=filecontent_table, })) -- Create a table with location items -- Containing all objects that start with % if (filecontent_table[1] == "%") then if not (locations[filecontent_table[2]]) then locations[filecontent_table[2]] = {} end table.insert(locations[filecontent_table[2]], filecontent_table[3]) end -- Create domain information tables local domain, level1, level2, level3, level4, level5, level6, levels if (filecontent_table[1] == "&") then local descr=check_signs("prefix") domain = format.string_to_table(filecontent_table[2], "%.") domaindetails = cfe ({ name=filecontent_table[2], label=descr[filecontent_table[1]], value=filecontent_table[2], }) end local value = filecontent_table[2] local currenttable if (type(domain) == "table") then currenttable = recursedomains(domain, domains, table.maxn(domain)) end -- FIXME: This is where we should put the information into the table! if (domaindetails.value) then table.insert (currenttable , domaindetails) end --[[ if (type(domain) == "table") then levels = table.maxn(domain) level1 = domain[levels] if (level1) then level2 = (domain[levels-1] or "unknown") .. "." end if (level2) and (domain[levels-2]) then level3 = domain[levels-2] .. "." .. level2 end if (level3) and (domain[levels-3]) then level4 = domain[levels-3] .. "." .. level3 end if (level4) and (domain[levels-4]) then level5 = domain[levels-4] .. "." .. level4 end if (level5) and (domain[levels-5]) then level6 = domain[levels-5] .. "." .. level5 end if (level6) and (domain[levels-6]) then level7 = domain[(levels-6)] .. "." .. level6 end end if (level1 ) and (#level1 > 0) and not (domain[levels] == "arpa") then if not (domains[level1]) then domains[level1] = {} end if (level2) and (#level2 > 0) then if not (domains[level1][level2]) then domains[level1][level2] = {} end if (level3) and (#level3 > 0) then if not (domains[level1][level2][level3]) then domains[level1][level2][level3] = {} end if (level4) and (#level4 > 0) then if not (domains[level1][level2][level3][level4]) then domains[level1][level2][level3][level4] = {} end if (level5) and (#level5 > 0) then if not (domains[level1][level2][level3][level4][level5]) then domains[level1][level2][level3][level4][level5] = {} end if (level6) and (#level6 > 0) then if not (domains[level1][level2][level3][level4][level5][level6]) then domains[level1][level2][level3][level4][level5][level6] = {} end if (level7) and (#level7 > 0) then if not (domains[level1][level2][level3][level4][level5][level6][level7]) then domains[level1][level2][level3][level4][level5][level6][level7] = {} domains[level1][level2][level3][level4][level5][level6][level7] = {} end else table.insert(domains[level1][level2][level3][level4][level5][level6], filecontent_table[4]) end --level7 else table.insert(domains[level1][level2][level3][level4][level5], filecontent_table[4]) end --level6 else table.insert(domains[level1][level2][level3][level4], filecontent_table[4]) end --level5 else table.insert(domains[level1][level2][level3], filecontent_table[4]) end --level4 else table.insert(domains[level1][level2], filecontent_table[4]) end --level3 else table.insert(domains[level1], filecontent_table[4]) end --level2 end --level1 --]] end end config.locations = cfe({ name="locations", label="Locations", value=locations, }) config.domains = cfe({ name="domains", label="Domains", value=domains, }) -- config.domains = debug ---[[ config.configitems = cfe({ name = "configitems", label="Config items", value=configobjects, }) --]] return config end -- ################################################################################ -- DEBUG INFORMATION (Everything below will be deleted in the future) function getdebug() local debug = {} --[[ local signs = get_available_signs("prefix") or {} debug.debugprefixes = cfe({ name = "debugprefixes", label="Available prefixes", option=signs, type="select", size=table.maxn(signs)+1, }) local signs = get_available_signs("suffix") or {} debug.debugsuffixes = cfe({ name = "debugsuffixes", label="Available suffixes", option=signs, type="select", size=table.maxn(signs)+1, }) --]] debug.configdir = cfe({ name = "configdir", label="configdir", value=configdir, }) debug.datafile = cfe({ name = "datafile", label="datafile", value=datafile, }) for k,v in pairs(configfiles) do local cnfcontent fake, cnfcontent = get_value_from_file(v) for kk,vv in pairs(cnfcontent) do table.insert(configitems,vv) end end ---[[ debug.configitems = cfe({ name = "configitems", label="configitems", option=configitems, type="select", }) --]] debug.configfiles = cfe({ name = "configfiles", label="configfiles", option=configfiles, type="select", }) return debug end