diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/core/luasrc/sys.lua | 280 |
1 files changed, 195 insertions, 85 deletions
diff --git a/libs/core/luasrc/sys.lua b/libs/core/luasrc/sys.lua index 9f25b84b30..45e44b80d1 100644 --- a/libs/core/luasrc/sys.lua +++ b/libs/core/luasrc/sys.lua @@ -12,9 +12,9 @@ Copyright 2008 Steven Barth <steven@midlink.org> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at +You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -24,13 +24,15 @@ limitations under the License. ]]-- +--- LuCI system utilities. module("luci.sys", package.seeall) require("posix") require("luci.bits") require("luci.util") require("luci.fs") --- Returns whether a system is bigendian +--- Test wheather the current system is operating in big endian mode. +-- @return Boolean value indicating wheather system is big endian function bigendian() local fp = io.open("/bin/sh") fp:seek("set", 5) @@ -39,72 +41,105 @@ function bigendian() return be end --- Runs "command" and returns its output +--- Execute given commandline and gather stdout. +-- @param command String containing command to execute +-- @return String containing the command's stdout function exec(command) local pp = io.popen(command) local data = pp:read("*a") pp:close() - + return data end --- Runs "command" and returns its output as a array of lines +--- Execute given commandline and gather stdout. +-- @param command String containing the command to execute +-- @return Table containing the command's stdout splitted up in lines function execl(command) - local pp = io.popen(command) + local pp = io.popen(command) local line = "" local data = {} - + while true do line = pp:read() if (line == nil) then break end table.insert(data, line) - end - pp:close() - + end + pp:close() + return data end --- Uses "luci-flash" to flash a new image file to the system +--- Invoke the luci-flash executable to write an image to the flash memory. +-- @param kpattern kpattern (ToDo: clearify this) +-- @return Return value of os.execute() function flash(image, kpattern) local cmd = "luci-flash " if kpattern then cmd = cmd .. "-k '" .. kpattern:gsub("'", "") .. "' " end cmd = cmd .. "'" .. image:gsub("'", "") .. "' >/dev/null 2>&1" - + return os.execute(cmd) end --- Returns the enivornment +--- Retrieve environment variables. If no variable is given then a table +-- containing the whole environment is returned otherwise this function returns +-- the corresponding string value for the given name or nil if no such variable +-- exists. +-- @class function +-- @name getenv +-- @param var Name of the environment variable to retrieve (optional) +-- @return String containg the value of the specified variable +-- @return Table containing all variables if no variable name is given getenv = posix.getenv --- Returns the hostname +--- Determine the current hostname. +-- @return String containing the system hostname function hostname() return io.lines("/proc/sys/kernel/hostname")() end --- Returns the contents of a documented referred by an URL +--- Returns the contents of a documented referred by an URL. +-- @param url The URL to retrieve +-- @return String containing the contents of given the URL function httpget(url) return exec("wget -qO- '"..url:gsub("'", "").."'") end --- Returns the FFLuci-Basedir +--- Returns the absolute path to LuCI base directory. +-- @return String containing the directory path function libpath() return luci.fs.dirname(require("luci.debug").__file__) end --- Returns the load average +--- Returns the system load average values. +-- @return String containing the average load value 1 minute ago +-- @return String containing the average load value 5 minutes ago +-- @return String containing the average load value 15 minutes ago +-- @return String containing the active and total number of processes +-- @return String containing the last used pid function loadavg() local loadavg = io.lines("/proc/loadavg")() return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$") end --- Reboots the system +--- Initiate a system reboot. +-- @return Return value of os.execute() function reboot() return os.execute("reboot >/dev/null 2>&1") end --- Returns the system type, cpu name, and installed physical memory +--- Returns the system type, cpu name and installed physical memory. +-- @return String containing the system or platform identifier +-- @return String containing hardware model information +-- @return String containing the total memory amount in kB +-- @return String containing the memory used for caching in kB +-- @return String containing the memory used for buffering in kB +-- @return String containing the free memory amount in kB +-- @return Number containing free memory in percent +-- @return Number containing buffer memory in percent +-- @return Number containing cache memory in percent function sysinfo() local c1 = "cat /proc/cpuinfo|grep system\\ typ|cut -d: -f2 2>/dev/null" local c2 = "uname -m 2>/dev/null" @@ -114,9 +149,9 @@ function sysinfo() local c6 = "cat /proc/meminfo|grep ^Cached|awk {' print $2 '} 2>/dev/null" local c7 = "cat /proc/meminfo|grep MemFree|awk {' print $2 '} 2>/dev/null" local c8 = "cat /proc/meminfo|grep Buffers|awk {' print $2 '} 2>/dev/null" - + local system = luci.util.trim(exec(c1)) - local model = "" + local model = "" local memtotal = luci.util.trim(exec(c5)) local memcached = luci.util.trim(exec(c6)) local memfree = luci.util.trim(exec(c7)) @@ -135,65 +170,86 @@ function sysinfo() return system, model, memtotal, memcached, membuffers, memfree, perc_memfree, perc_membuffers, perc_memcached end --- Reads the syslog +--- Retrieves the output of the "logread" command. +-- @return String containing the current log buffer function syslog() return exec("logread") end - --- Generates a random key of length BYTES +--- Generates a random id with specified length. +-- @param bytes Number of bytes for the unique id +-- @return String containing hex encoded id function uniqueid(bytes) local fp = io.open("/dev/urandom") local chunk = { fp:read(bytes):byte(1, bytes) } fp:close() - + local hex = "" - - local pattern = "%02X" + + local pattern = "%02X" for i, byte in ipairs(chunk) do hex = hex .. pattern:format(byte) end - + return hex end - --- Returns uptime stats +--- Returns the current system uptime stats. +-- @return String containing total uptime in seconds +-- @return String containing idle time in seconds function uptime() local loadavg = io.lines("/proc/uptime")() return loadavg:match("^(.-) (.-)$") end - +--- Get group information +-- @return Group (ToDo: clearify) group = {} group.getgroup = posix.getgroup + +--- LuCI system utilities / network related functions. +-- @class module +-- @name luci.sys.net net = {} --- Returns the ARP-Table + +--- Returns the current arp-table entries as two-dimensional table. +-- @return Table of table containing the current arp entries. +-- The following fields are defined for arp entry objects: +-- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" } function net.arptable() return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+") end --- Returns whether an IP-Adress belongs to a certain net +--- Test whether an IP-Adress belongs to a certain net. +-- @param ip IPv4 address to test +-- @param ipnet IPv4 network address of the net range to compare against +-- @param prefix Network prefix of the net range to compare against +-- @return Boolean indicating wheather the ip is within the range function net.belongs(ip, ipnet, prefix) return (net.ip4bin(ip):sub(1, prefix) == net.ip4bin(ipnet):sub(1, prefix)) end --- Detect the default route +--- Determine the current default route. +-- @return Table with the properties of the current default route. +-- The following fields are defined: +-- { "Mask", "RefCnt", "Iface", "Flags", "Window", "IRTT", +-- "MTU", "Gateway", "Destination", "Metric", "Use" } function net.defaultroute() local routes = net.routes() local route = nil - + for i, r in pairs(luci.sys.net.routes()) do if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then route = r end end - + return route end --- Returns all available network interfaces +--- Determine the names of available network interfaces. +-- @return Table containing all current interface names function net.devices() local devices = {} for line in io.lines("/proc/net/dev") do @@ -202,45 +258,56 @@ function net.devices() return devices end --- Returns the MAC-Address belonging to the given IP-Address +-- Determine the MAC address belonging to the given IP address. +-- @param ip IPv4 address +-- @return String containing the MAC address or nil if it cannot be found function net.ip4mac(ip) local mac = nil - + for i, l in ipairs(net.arptable()) do if l["IP address"] == ip then mac = l["HW address"] end end - + return mac end --- Returns the prefix to a given netmask +--- Calculate the prefix from a given netmask. +-- @param mask IPv4 net mask +-- @return Number containing the corresponding numerical prefix function net.mask4prefix(mask) local bin = net.ip4bin(mask) - + if not bin then return nil end - + return #luci.util.split(bin, "1")-1 end --- Returns the kernel routing table +--- Returns the current kernel routing table entries. +-- @return Table of tables with properties of the corresponding routes. +-- The following fields are defined for route entry tables: +-- { "Mask", "RefCnt", "Iface", "Flags", "Window", "IRTT", +-- "MTU", "Gateway", "Destination", "Metric", "Use" } function net.routes() return _parse_delimited_table(io.lines("/proc/net/route")) end --- Returns the numeric IP to a given hexstring +--- Convert hexadecimal 32 bit value to IPv4 address. +-- @param hex String containing the hexadecimal value +-- @param be Boolean indicating wheather the given value is big endian +-- @return String containing the corresponding IP4 address function net.hexip4(hex, be) if #hex ~= 8 then return nil end - + be = be or bigendian() - + local hexdec = luci.bits.Hex2Dec - + local ip = "" if be then ip = ip .. tostring(hexdec(hex:sub(1,2))) .. "." @@ -253,55 +320,88 @@ function net.hexip4(hex, be) ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "." ip = ip .. tostring(hexdec(hex:sub(1,2))) end - + return ip end --- Returns the binary IP to a given IP +--- Convert given IPv4 address to binary value. +-- @param ip String containing a IPv4 address +-- @return String containing corresponding binary value function net.ip4bin(ip) local parts = luci.util.split(ip, '.') if #parts ~= 4 then return nil end - + local decbin = luci.bits.Dec2Bin - + local bin = "" bin = bin .. decbin(parts[1], 8) bin = bin .. decbin(parts[2], 8) bin = bin .. decbin(parts[3], 8) bin = bin .. decbin(parts[4], 8) - + return bin end --- Tests whether a host is pingable +--- Tests whether the given host responds to ping probes. +-- @param host String containing a hostname or IPv4 address +-- @return Number containing 0 on success and >= 1 on error function net.pingtest(host) return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1") end +--- LuCI system utilities / process related functions. +-- @class module +-- @name luci.sys.process process = {} -process.info = posix.getpid --- Sets the gid of a process +--- Get the current process id. +-- @return Number containing the current pid +process.info = posix.getpid + +--- Set the gid of a process identified by given pid. +-- @param pid Number containing the process id +-- @param gid Number containing the Unix group id +-- @return Boolean indicating successful operation +-- @return String containing the error message if failed +-- @return Number containing the error code if failed function process.setgroup(pid, gid) return posix.setpid("g", pid, gid) end --- Sets the uid of a process +--- Set the uid of a process identified by given pid. +-- @param pid Number containing the process id +-- @param uid Number containing the Unix user id +-- @return Boolean indicating successful operation +-- @return String containing the error message if failed +-- @return Number containing the error code if failed function process.setuser(pid, uid) return posix.setpid("u", pid, uid) end + +--- LuCI system utilities / user related functions. +-- @class module +-- @name luci.sys.user user = {} --- returns user information to a given uid + +--- Retrieve user informations for given uid. +-- @class function +-- @name getuser +-- @param uid Number containing the Unix user id +-- @return Table containing the following fields: +-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" } user.getuser = posix.getpasswd --- checks whether a string matches the password of a certain system user +--- Test whether given string matches the password of a given system user. +-- @param username String containing the Unix user name +-- @param password String containing the password to compare +-- @return Boolean indicating wheather the passwords are equal function user.checkpasswd(username, password) local account = user.getuser(username) - + -- FIXME: detect testing environment if luci.fs.stat("/etc/shadow") and not luci.fs.access("/etc/shadow", "r") then return true @@ -313,29 +413,37 @@ function user.checkpasswd(username, password) end end end - --- Changes the user password of given user -function user.setpasswd(user, pwd) - if pwd then - pwd = pwd:gsub("'", "") + +--- Change the password of given user. +-- @param username String containing the Unix user name +-- @param password String containing the password to compare +-- @return Number containing 0 on success and >= 1 on error +function user.setpasswd(username, password) + if password then + password = password:gsub("'", "") end - - if user then - user = user:gsub("'", "") + + if username then + username = username:gsub("'", "") end - - local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|" - cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1" + + local cmd = "(echo '"..password.."';sleep 1;echo '"..password.."')|" + cmd = cmd .. "passwd '"..username.."' >/dev/null 2>&1" return os.execute(cmd) end +--- LuCI system utilities / wifi related functions. +-- @class module +-- @name luci.sys.wifi wifi = {} +--- Get iwconfig output for all wireless devices. +-- @return Table of tables containing the iwconfing output for each wifi device function wifi.getiwconfig() local cnt = exec("/usr/sbin/iwconfig 2>/dev/null") local iwc = {} - + for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do local k = l:match("^(.-) ") l = l:gsub("^(.-) +", "", 1) @@ -343,14 +451,16 @@ function wifi.getiwconfig() iwc[k] = _parse_mixed_record(l) end end - - return iwc + + return iwc end +--- Get iwlist scan output from all wireless devices. +-- @return Table of tables contaiing all scan results function wifi.iwscan() local cnt = exec("iwlist scan 2>/dev/null") local iws = {} - + for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do local k = l:match("^(.-) ") l = l:gsub("^[^\n]+", "", 1) @@ -365,8 +475,8 @@ function wifi.iwscan() end end end - - return iws + + return iws end @@ -374,16 +484,16 @@ end function _parse_delimited_table(iter, delimiter) delimiter = delimiter or "%s+" - + local data = {} local trim = luci.util.trim local split = luci.util.split - + local keys = split(trim(iter()), delimiter, nil, true) for i, j in pairs(keys) do keys[i] = trim(keys[i]) end - + for line in iter do local row = {} line = trim(line) @@ -396,26 +506,26 @@ function _parse_delimited_table(iter, delimiter) end table.insert(data, row) end - + return data end function _parse_mixed_record(cnt) local data = {} - + for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do for j, f in pairs(luci.util.split(luci.util.trim(l), " ")) do local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*') if k then if x == "" then - table.insert(data, k) + table.insert(data, k) else data[k] = v end end end end - + return data end |