-- acf model for displaying logfiles module (..., package.seeall) require("fs") require("posix") require("format") require("modelfunctions") -- Function to get detailed information on a specific file. local function file_info ( path ) -- Check if file is in use local st = fs.stat(path) while st.type == "link" do st = fs.stat(posix.readlink(st.path)) end local size = st.size or "0" local lastmod = st.mtime or "---" local file_inuse = io.popen("fuser " .. format.escapespecialcharacters(path) ) local fileinuseresult = file_inuse:read("*a") or "unknown" file_inuse:close() fileinuseresult = (fileinuseresult ~= "") return lastmod,size,fileinuseresult end -- Function to recursively insert all filenames in a dir into an array local function recursedir(path, filearray) filearray = filearray or {} 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 local st = fs.stat(f) while st and st.type == "link" do st = fs.stat(posix.readlink(st.path)) end if st and st.type == "directory" then recursedir(f, filearray) elseif st then table.insert(filearray, f) end end end return filearray end -- Function to list available files for view/delete local function list_files ( ... ) local listed_files = {} local open_files = {} local files = {} local k,v -- Generate a single table with all the files for k,v in pairs{...} do recursedir(v, files) end -- Loop through each file and present its info for k,v in pairs(files) do -- Get info on this specific file and put it in a table local lastmod,size,fileinuseresult = file_info(v) local filename = cfe({ value=v, label="File name" }) local filesize = cfe({ value=size, label="File size" }) local mtime = cfe({ value=lastmod, label="File date" }) local inuse = cfe({ type="boolean", value=fileinuseresult, label="File in use" }) table.insert ( listed_files , cfe({ type="group", value={filename=filename, filesize=filesize, mtime=mtime, inuse=inuse, label="File details"} }) ) end table.sort(listed_files, function (a,b) return (a.value.filename.value < b.value.filename.value) end ) return cfe({ type="list", value=listed_files, label="Log files" }) end local do_grep = function(filecontent, grep) if grep and grep ~= "" then local lines = {} for line in string.gmatch(filecontent.value, "[^\n]*\n?") do if string.match(line, grep) then lines[#lines+1] = line end end filecontent.value = table.concat(lines) or "" end end get_filedetails = function (path, grep) local success = false local available_files = get() for i,file in ipairs(available_files.value) do if file.value.filename.value == path then success = true break end end local file = path if success then local st = fs.stat(path) while st.type == "link" do st = fs.stat(posix.readlink(st.path)) end file = st.path end local filedetails = modelfunctions.getfiledetails(file, function(filename) return success end) filedetails.value.filename.value = path if not filedetails.errtxt then do_grep(filedetails.value.filecontent, grep) end filedetails.value.grep = cfe({ value=grep or "", label="Grep" }) return filedetails end tail = function(path, offset, grep) local filename = cfe({ value=path, label="File name", errtxt="File not found" }) local filesize = cfe({ value="0", label="File size" }) local filecontent = cfe({ type="longtext", label="File content" }) local fileoffset = cfe({ value="0", label="File offset" }) local filegrep = cfe({ value=grep or "", label="Grep" }) local available_files = get() for i,file in ipairs(available_files.value) do if ( file.value.filename.value == path ) then filename.errtxt = nil local f = io.open(path) if tonumber(offset) then fileoffset.value = offset offset = tonumber(offset) if offset < 0 then f:seek("end", offset) else f:seek("set", offset) end filecontent.value = f:read("*all") filesize.value = f:seek() else filesize.value = f:seek("end") fileoffset.value = filesize.value end f:close() do_grep(filecontent, grep) break end end return cfe({ type="group", value={filename=filename, filecontent=filecontent, filesize=filesize, fileoffset=fileoffset, grep=filegrep}, label="Tail Config file details" }) end get = function () -- These folders (and their subfolers) are going to be listed return list_files( "/var/log", "/tmp/squid/log" ) end -- Function to check if a file is deletable, and if it is, then delete it. delete = function (filetodelete) local deletedfile = cfe({ label="Delete result", value="File '" .. filetodelete .. "' has not been deleted!" }) -- Get a list of files that could be deleted local available_files = get() for i,file in ipairs(available_files.value) do if ( file.value.filename.value == filetodelete ) then -- Check if file is deletable (or in use) if ( not file.value.inuse.value ) then local st = fs.stat(filetodelete) while st.type == "link" do st = fs.stat(posix.readlink(st.path)) end local status, err = os.remove( st.path ) if not ( err ) then deletedfile.value = "File '"..filetodelete.."' has been successfully deleted!" else deletedfile.errtxt = err end end break end end return deletedfile end