--[[ POSIX library for Lua 5.1, 5.2 & 5.3. (c) Gary V. Vaughan , 2014-2015 ]] --[[-- Legacy Lua POSIX bindings. Undocumented Legacy APIs for compatibility with previous releases. @module posix.deprecated ]] local _argcheck = require "posix._argcheck" local bit = require "bit32" -- Lua 5.3 has table.unpack but not _G.unpack -- Lua 5.2 has table.unpack and _G.unpack -- Lua 5.1 has _G.unpack but not table.unpack local unpack = table.unpack or unpack local argerror, argtypeerror, badoption = _argcheck.argerror, _argcheck.argtypeerror, _argcheck.badoption local band, bnot, bor = bit.band, bit.bnot, bit.bor local checkint, checkselection, checkstring, checktable = _argcheck.checkint, _argcheck.checkselection, _argcheck.checkstring, _argcheck.checktable local optint, optstring, opttable = _argcheck.optint, _argcheck.optstring, _argcheck.opttable local toomanyargerror = _argcheck.toomanyargerror -- Convert a legacy API tm table to a posix.time.PosixTm compatible table. local function PosixTm (legacytm) return { tm_sec = legacytm.sec, tm_min = legacytm.min, tm_hour = legacytm.hour, -- For compatibility with Lua os.date() use "day" if "monthday" is -- not set. tm_mday = legacytm.monthday or legacytm.day, tm_mon = legacytm.month - 1, tm_year = legacytm.year - 1900, tm_wday = legacytm.weekday, tm_yday = legacytm.yearday, tm_isdst = legacytm.is_dst and 1 or 0, } end -- Convert a posix.time.PosixTm into a legacy API tm table. local function LegacyTm (posixtm) return { sec = posixtm.tm_sec, min = posixtm.tm_min, hour = posixtm.tm_hour, monthday = posixtm.tm_mday, day = posixtm.tm_mday, month = posixtm.tm_mon + 1, year = posixtm.tm_year + 1900, weekday = posixtm.tm_wday, yearday = posixtm.tm_yday, is_dst = posixtm.tm_isdst ~= 0, } end local function doselection (name, argoffset, fields, map) if #fields == 1 and type (fields[1]) == "table" then fields = fields[1] end if not (next (fields)) then return map else local r = {} for i, v in ipairs (fields) do if map[v] then r[#r + 1] = map[v] else argerror (name, i + argoffset, "invalid option '" .. v .. "'", 2) end end return unpack (r) end end local st = require "posix.sys.stat" local S_IRUSR, S_IWUSR, S_IXUSR = st.S_IRUSR, st.S_IWUSR, st.S_IXUSR local S_IRGRP, S_IWGRP, S_IXGRP = st.S_IRGRP, st.S_IWGRP, st.S_IXGRP local S_IROTH, S_IWOTH, S_IXOTH = st.S_IROTH, st.S_IWOTH, st.S_IXOTH local S_ISUID, S_ISGID, S_IRWXU, S_IRWXG, S_IRWXO = st.S_ISUID, st.S_ISGID, st.S_IRWXU, st.S_IRWXG, st.S_IRWXO local mode_map = { { c = "r", b = S_IRUSR }, { c = "w", b = S_IWUSR }, { c = "x", b = S_IXUSR }, { c = "r", b = S_IRGRP }, { c = "w", b = S_IWGRP }, { c = "x", b = S_IXGRP }, { c = "r", b = S_IROTH }, { c = "w", b = S_IWOTH }, { c = "x", b = S_IXOTH }, } local function pushmode (mode) local m = {} for i = 1, 9 do if band (mode, mode_map[i].b) ~= 0 then m[i] = mode_map[i].c else m[i] = "-" end end if band (mode, S_ISUID) ~= 0 then if band (mode, S_IXUSR) ~= 0 then m[3] = "s" else m[3] = "S" end end if band (mode, S_ISGID) ~= 0 then if band (mode, S_IXGRP) ~= 0 then m[6] = "s" else m[6] = "S" end end return table.concat (m) end local M = {} --- Bind an address to a socket. -- @function bind -- @int fd socket descriptor to act on -- @tparam PosixSockaddr addr socket address -- @treturn[1] bool `true`, if successful -- @return[2] nil -- @treturn[2] string error messag -- @treturn[2] int errnum -- @see bind(2) local sock = require "posix.sys.socket" local bind = sock.bind function M.bind (...) local rt = { bind (...) } if rt[1] == 0 then return true end return unpack (rt) end --- Find the precision of a clock. -- @function clock_getres -- @string[opt="realtime"] name name of clock, one of "monotonic", -- "process\_cputime\_id", "realtime", or "thread\_cputime\_id" -- @treturn[1] int seconds -- @treturn[21 int nanoseconds, if successful -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum -- @see clock_getres(3) local tm = require "posix.time" local _clock_getres = tm.clock_getres local function get_clk_id_const (name) local map = { monotonic = tm.CLOCK_MONOTONIC, process_cputime_id = tm.CLOCK_PROCESS_TIME_ID, thread_cputime_id = tm.CLOCK_THREAD_CPUTIME_ID, } return map[name] or tm.CLOCK_REALTIME end local function clock_getres (name) local ts = _clock_getres (get_clk_id_const (name)) return ts.tv_sec, ts.tv_nsec end if _clock_getres == nil then -- Not supported by underlying system elseif _DEBUG ~= false then M.clock_getres = function (...) local argt = {...} optstring ("clock_getres", 1, argt[1], "realtime") if #argt > 1 then toomanyargerror ("clock_getres", 1, #argt) end return clock_getres (...) end else M.clock_getres = clock_getres end --- Read a clock -- @function clock_gettime -- @string[opt="realtime"] name name of clock, one of "monotonic", -- "process\_cputime\_id", "realtime", or "thread\_cputime\_id" -- @treturn[1] int seconds -- @treturn[21 int nanoseconds, if successful -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum -- @see clock_gettime(3) local tm = require "posix.time" local _clock_gettime = tm.clock_gettime local function clock_gettime (name) local ts = _clock_gettime (get_clk_id_const (name)) return ts.tv_sec, ts.tv_nsec end if _clock_gettime == nil then -- Not supported by underlying system elseif _DEBUG ~= false then M.clock_gettime = function (...) local argt = {...} optstring ("clock_gettime", 1, argt[1], "realtime") if #argt > 1 then toomanyargerror ("clock_gettime", 1, #argt) end return clock_gettime (...) end else M.clock_gettime = clock_gettime end --- Initiate a connection on a socket. -- @function connect -- @int fd socket descriptor to act on -- @tparam PosixSockaddr addr socket address -- @treturn[1] bool `true`, if successful -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum -- @see connect(2) local sock = require "posix.sys.socket" local connect = sock.connect function M.connect (...) local rt = { connect (...) } if rt[1] == 0 then return true end return unpack (rt) end --- Execute a program without using the shell. -- @function exec -- @string path -- @tparam[opt] table|strings ... table or tuple of arguments (table can include index 0) -- @return nil -- @treturn string error message -- @see execve(2) local unistd = require "posix.unistd" local _exec = unistd.exec local function exec (path, ...) local argt = {...} if #argt == 1 and type (argt[1]) == "table" then argt = argt[1] end return _exec (path, argt) end if _DEBUG ~= false then M.exec = function (...) local argt = {...} checkstring ("exec", 1, argt[1]) if type (argt[2]) ~= "table" and type (argt[2]) ~= "string" and type (argt[2]) ~= "nil" then argtypeerror ("exec", 2, "string, table or nil", argt[2]) end if #argt > 2 then if type (argt[2]) == "table" then toomanyargerror ("exec", 2, #argt) else for i = 3, #argt do checkstring ("exec", i, argt[i]) end end end return exec (...) end else M.exec = exec end --- Execute a program with the shell. -- @function execp -- @string path -- @tparam[opt] table|strings ... table or tuple of arguments (table can include index 0) -- @return nil -- @treturn string error message -- @see execve(2) local unistd = require "posix.unistd" local _execp = unistd.execp local function execp (path, ...) local argt = {...} if #argt == 1 and type (argt[1]) == "table" then argt = argt[1] end return _execp (path, argt) end if _DEBUG ~= false then M.execp = function (...) local argt = {...} checkstring ("execp", 1, argt[1]) if type (argt[2]) ~= "table" and type (argt[2]) ~= "string" and type (argt[2]) ~= "nil" then argtypeerror ("execp", 2, "string, table or nil", argt[2]) end if #argt > 2 then if type (argt[2]) == "table" then toomanyargerror ("execp", 2, #argt) else for i = 3, #argt do checkstring ("execp", i, argt[i]) end end end return execp (...) end else M.execp = execp end --- Instruct kernel on appropriate cache behaviour for a file or file segment. -- @function fadvise -- @tparam file fh Lua file object -- @int offset start of region -- @int len number of bytes in region -- @int advice one of `POSIX_FADV_NORMAL, `POSIX_FADV_SEQUENTIAL, -- `POSIX_FADV_RANDOM`, `POSIX_FADV_\NOREUSE`, `POSIX_FADV_WILLNEED` or -- `POSIX_FADV_DONTNEED` -- @treturn[1] int `0`, if successful -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum -- @see posix_fadvise(2) local fc = require "posix.fcntl" local stdio = require "posix.stdio" local posix_fadvise = fc.posix_fadvise local fileno = stdio.fileno local function fadvise (fh, ...) return posix_fadvise (fileno (fh), ...) end if posix_fadvise == nil then -- Not supported by underlying system elseif _DEBUG ~= false then M.fadvise = function (...) argt = {...} if io.type (argt[1]) ~= "file" then argtypeerror ("fadvise", 1, "FILE*", argt[1]) end checkint ("fadvise", 2, argt[2]) checkint ("fadvise", 3, argt[3]) checkint ("fadvise", 4, argt[4]) if #argt > 4 then toomanyargerror ("fadvise", 4, #argt) end return fadvise (...) end else M.fadvise = fadvise end --- Match a filename against a shell pattern. -- @function fnmatch -- @string pat shell pattern -- @string name filename -- @return true or false -- @raise error if fnmatch failed -- @see posix.fnmatch.fnmatch local fnm = require "posix.fnmatch" function M.fnmatch (...) local r = fnm.fnmatch (...) if r == 0 then return true elseif r == fnm.FNM_NOMATCH then return false end error "fnmatch failed" end --- Group information. -- @table group -- @string name name of group -- @int gid unique group id -- @string ... list of group members --- Information about a group. -- @function getgroup -- @tparam[opt=current group] int|string group id or group name -- @treturn group group information -- @usage -- print (P.getgroup (P.getgid ()).name) local grp = require "posix.grp" local unistd = require "posix.unistd" local getgrgid, getgrnam = grp.getgrgid, grp.getgrnam local getegid = unistd.getegid local function getgroup (grp) if grp == nil then grp = getegid () end local g if type (grp) == "number" then g = getgrgid (grp) elseif type (grp) == "string" then g = getgrnam (grp) else argtypeerror ("getgroup", 1, "string, int or nil", grp) end if g ~= nil then return {name=g.gr_name, gid=g.gr_gid, mem=g.gr_mem} end end if _DEBUG ~= false then M.getgroup = function (...) local argt = {...} if #argt > 1 then toomanyargerror ("getgroup", 1, #argt) end return getgroup (...) end else M.getgroup = getgroup end --- Get the password entry for a user. -- @function getpasswd -- @tparam[opt=current user] int|string user name or id -- @string ... field names, each one of "uid", "name", "gid", "passwd", -- "dir" or "shell" -- @return ... values, or a table of all fields if *user* is `nil` -- @usage for a,b in pairs (P.getpasswd "root") do print (a, b) end -- @usage print (P.getpasswd ("root", "shell")) local pwd = require "posix.pwd" local unistd = require "posix.unistd" local getpwnam, getpwuid = pwd.getpwnam, pwd.getpwuid local geteuid = unistd.geteuid local function getpasswd (user, ...) if user == nil then user = geteuid () end local p if type (user) == "number" then p = getpwuid (user) elseif type (user) == "string" then p = getpwnam (user) else argtypeerror ("getpasswd", 1, "string, int or nil", user) end if p ~= nil then return doselection ("getpasswd", 1, {...}, { dir = p.pw_dir, gid = p.pw_gid, name = p.pw_name, passwd = p.pw_passwd, shell = p.pw_shell, uid = p.pw_uid, }) end end if _DEBUG ~= false then M.getpasswd = function (user, ...) checkselection ("getpasswd", 2, {...}, 2) return getpasswd (user, ...) end else M.getpasswd = getpasswd end --- Get process identifiers. -- @function getpid -- @tparam[opt] table|string type one of "egid", "euid", "gid", "uid", -- "pgrp", "pid" or "ppid"; or a single list of the same -- @string[opt] ... unless *type* was a table, zero or more additional -- type strings -- @return ... values, or a table of all fields if no option given -- @usage for a,b in pairs (P.getpid ()) do print (a, b) end -- @usage print (P.getpid ("uid", "euid")) local unistd = require "posix.unistd" local getegid, geteuid, getgid, getuid = unistd.getegid, unistd.geteuid, unistd.getgid, unistd.getuid local _getpid, getpgrp, getppid = unistd.getpid, unistd.getpgrp, unistd.getppid local function getpid (...) return doselection ("getpid", 0, {...}, { egid = getegid (), euid = geteuid (), gid = getgid (), uid = getuid (), pgrp = getpgrp (), pid = _getpid (), ppid = getppid (), }) end if _DEBUG ~= false then M.getpid = function (...) checkselection ("getpid", 1, {...}, 2) return getpid (...) end else M.getpid = getpid end --- Get resource limits for this process. -- @function getrlimit -- @string resource one of "core", "cpu", "data", "fsize", "nofile", -- "stack" or "as" -- @treturn[1] int soft limit -- @treturn[1] int hard limit, if successful -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum local resource = require "posix.sys.resource" local _getrlimit = resource.getrlimit local rlimit_map = { core = resource.RLIMIT_CORE, cpu = resource.RLIMIT_CPU, data = resource.RLIMIT_DATA, fsize = resource.RLIMIT_FSIZE, nofile = resource.RLIMIT_NOFILE, stack = resource.RLIMIT_STACK, as = resource.RLIMIT_AS, } local function getrlimit (rcstr) local rc = rlimit_map[string.lower (rcstr)] if rc == nil then argerror("getrlimit", 1, "invalid option '" .. rcstr .. "'") end local rlim = _getrlimit (rc) return rlim.rlim_cur, rlim.rlim_max end if _DEBUG ~= false then M.getrlimit = function (...) local argt = {...} checkstring ("getrlimit", 1, argt[1]) if #argt > 1 then toomanyargerror ("getrlimit", 1, #argt) end return getrlimit (...) end else M.getrlimit = getrlimit end --- Get time of day. -- @function gettimeofday -- @treturn timeval time elapsed since *epoch* -- @see gettimeofday(2) local systime = require "posix.sys.time" local gettimeofday = systime.gettimeofday function M.gettimeofday (...) local tv = gettimeofday (...) return { sec = tv.tv_sec, usec = tv.tv_usec } end --- Convert epoch time value to a broken-down UTC time. -- Here, broken-down time tables the month field is 1-based not -- 0-based, and the year field is the full year, not years since -- 1900. -- @function gmtime -- @int[opt=now] t seconds since epoch -- @treturn table broken-down time local tm = require "posix.time" local _gmtime, time = tm.gmtime, tm.time local function gmtime (epoch) return LegacyTm (_gmtime (epoch or time ())) end if _DEBUG ~= false then M.gmtime = function (...) local argt = {...} optint ("gmtime", 1, argt[1]) if #argt > 1 then toomanyargerror ("gmtime", 1, #argt) end return gmtime (...) end else M.gmtime = gmtime end --- Get host id. -- @function hostid -- @treturn int unique host identifier local unistd = require "posix.unistd" M.hostid = unistd.gethostid --- Check for any printable character except space. -- @function isgraph -- @see isgraph(3) -- @string character to act on -- @treturn bool non-`false` if character is in the class local ctype = require "posix.ctype" local isgraph = ctype.isgraph function M.isgraph (...) return isgraph (...) ~= 0 end --- Check for any printable character including space. -- @function isprint -- @string character to act on -- @treturn bool non-`false` if character is in the class -- @see isprint(3) local ctype = require "posix.ctype" local isprint = ctype.isprint function M.isprint (...) return isprint (...) ~= 0 end --- Convert epoch time value to a broken-down local time. -- Here, broken-down time tables the month field is 1-based not -- 0-based, and the year field is the full year, not years since -- 1900. -- @function localtime -- @int[opt=now] t seconds since epoch -- @treturn table broken-down time local tm = require "posix.time" local _localtime, time = tm.localtime, tm.time local function localtime (epoch) return LegacyTm (_localtime (epoch or time ())) end if _DEBUG ~= false then M.localtime = function (...) local argt = {...} optint ("localtime", 1, argt[1]) if #argt > 1 then toomanyargerror ("localtime", 1, #argt) end return localtime (...) end else M.localtime = localtime end --- Convert a broken-down localtime table into an epoch time. -- @function mktime -- @tparam tm broken-down localtime table -- @treturn in seconds since epoch -- @see mktime(3) -- @see localtime local tm = require "posix.time" local _mktime, localtime, time = tm.mktime, tm.localtime, tm.time local function mktime (legacytm) local posixtm = legacytm and PosixTm (legacytm) or localtime (time ()) return _mktime (posixtm) end if _DEBUG ~= false then M.mktime = function (...) local argt = {...} opttable ("mktime", 1, argt[1]) if #argt > 1 then toomanyargerror ("mktime", 1, #argt) end return mktime (...) end else M.mktime = mktime end --- Sleep with nanosecond precision. -- @function nanosleep -- @int seconds requested sleep time -- @int nanoseconds requested sleep time -- @treturn[1] int `0` if requested time has elapsed -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum -- @treturn[2] int unslept seconds remaining, if interrupted -- @treturn[2] int unslept nanoseconds remaining, if interrupted -- @see nanosleep(2) -- @see posix.unistd.sleep local tm = require "posix.time" local _nanosleep = tm.nanosleep local function nanosleep (sec, nsec) local r, errmsg, errno, timespec = _nanosleep {tv_sec = sec, tv_nsec = nsec} if r == 0 then return 0 end return r, errmsg, errno, timespec.tv_sec, timespec.tv_nsec end if _DEBUG ~= false then M.nanosleep = function (...) local argt = {...} checkint ("nanosleep", 1, argt[1]) checkint ("nanosleep", 2, argt[2]) if #argt > 2 then toomanyargerror ("nanosleep", 2, #argt) end return nanosleep (...) end else M.nanosleep = nanosleep end --- Open the system logger. -- @function openlog -- @string ident all messages will start with this -- @string[opt] option any combination of 'c' (directly to system console -- if an error sending), 'n' (no delay) and 'p' (show PID) -- @int [opt=`LOG_USER`] facility one of `LOG_AUTH`, `LOG_AUTHORITY`, -- `LOG_CRON`, `LOG_DAEMON`, `LOG_FTP`, `LOG_KERN`, `LOG_LPR`, `LOG_MAIL`, -- `LOG_NEWS`, `LOG_SECURITY`, `LOG_SYSLOG`, `LOG_USER`, `LOG_UUCP` or -- `LOG_LOCAL0` through `LOG_LOCAL7` -- @see syslog(3) local bit = require "bit32" local log = require "posix.syslog" local bor = bit.bor local _openlog = log.openlog local optionmap = { [' '] = 0, c = log.LOG_CONS, n = log.LOG_NDELAY, p = log.LOG_PID, } local function openlog (ident, optstr, facility) local option = 0 if optstr then for i = 1, #optstr do local c = optstr:sub (i, i) if optionmap[c] == nil then badoption ("openlog", 2, "openlog", c) end option = bor (option, optionmap[c]) end end return _openlog (ident, option, facility) end if _DEBUG ~= false then M.openlog = function (...) local argt = {...} checkstring ("openlog", 1, argt[1]) optstring ("openlog", 2, argt[2]) optint ("openlog", 3, argt[3]) if #argt > 3 then toomanyargerror ("openlog", 3, #argt) end return openlog (...) end else M.openlog = openlog end --- Get configuration information at runtime. -- @function pathconf -- @string[opt="."] path file to act on -- @tparam[opt] table|string key one of "CHOWN_RESTRICTED", "LINK_MAX", -- "MAX_CANON", "MAX_INPUT", "NAME_MAX", "NO_TRUNC", "PATH_MAX", "PIPE_BUF" -- or "VDISABLE" -- @string[opt] ... unless *type* was a table, zero or more additional -- type strings -- @return ... values, or a table of all fields if no option given -- @see sysconf(2) -- @usage for a,b in pairs (P.pathconf "/dev/tty") do print (a, b) end local unistd = require "posix.unistd" local _pathconf = unistd.pathconf local Spathconf = { CHOWN_RESTRICTED = 1, LINK_MAX = 1, MAX_CANON = 1, MAX_INPUT = 1, NAME_MAX = 1, NO_TRUNC = 1, PATH_MAX = 1, PIPE_BUF = 1, VDISABLE = 1 } local function pathconf (path, ...) local argt, map = {...}, {} if path ~= nil and Spathconf[path] ~= nil then path, argt = ".", {path, ...} end for k in pairs (Spathconf) do map[k] = _pathconf (path or ".", unistd["_PC_" .. k]) end return doselection ("pathconf", 1, {...}, map) end if _DEBUG ~= false then M.pathconf = function (path, ...) if path ~= nil and Spathconf[path] ~= nil then checkselection ("pathconf", 1, {path, ...}, 2) else optstring ("pathconf", 1, path, ".", 2) checkselection ("pathconf", 2, {...}, 2) end return pathconf (path, ...) end else M.pathconf = pathconf end --- Set resource limits for this process. -- @function setrlimit -- @string resource one of "core", "cpu", "data", "fsize", "nofile", -- "stack" or "as" -- @int[opt] softlimit process may receive a signal when reached -- @int[opt] hardlimit process may be terminated when reached -- @treturn[1] int `0`, if successful -- @return[2] nil -- @treturn[2] string error message -- @treturn[2] int errnum local resource = require "posix.sys.resource" local _setrlimit = resource.setrlimit local rlimit_map = { core = resource.RLIMIT_CORE, cpu = resource.RLIMIT_CPU, data = resource.RLIMIT_DATA, fsize = resource.RLIMIT_FSIZE, nofile = resource.RLIMIT_NOFILE, stack = resource.RLIMIT_STACK, as = resource.RLIMIT_AS, } local function setrlimit (rcstr, cur, max) local rc = rlimit_map[string.lower (rcstr)] if rc == nil then argerror("setrlimit", 1, "invalid option '" .. rcstr .. "'") end local lim if cur == nil or max == nil then lim= _getrlimit (rc) end return _setrlimit (rc, { rlim_cur = cur or lim.rlim_cur, rlim_max = max or lim.rlim_max, }) end if _DEBUG ~= false then M.setrlimit = function (...) local argt = {...} checkstring ("setrlimit", 1, argt[1]) optint ("setrlimit", 2, argt[2]) optint ("setrlimit", 3, argt[3]) if #argt > 3 then toomanyargerror ("setrlimit", 3, #argt) end return setrlimit (...) end else M.getrlimit = getrlimit end --- Information about an existing file path. -- If the file is a symbolic link, return information about the link -- itself. -- @function stat -- @string path file to act on -- @tparam[opt] table|string field one of "dev", "ino", "mode", "nlink", -- "uid", "gid", "rdev", "size", "atime", "mtime", "ctime" or "type" -- @string[opt] ... unless *field* was a table, zero or more additional -- field names -- @return values, or table of all fields if no option given -- @see stat(2) -- @usage for a,b in pairs (P,stat "/etc/") do print (a, b) end local st = require "posix.sys.stat" local S_ISREG, S_ISLNK, S_ISDIR, S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK = st.S_ISREG, st.S_ISLNK, st.S_ISDIR, st.S_ISCHR, st.S_ISBLK, st.S_ISFIFO, st.S_ISSOCK local function filetype (mode) if S_ISREG (mode) ~= 0 then return "regular" elseif S_ISLNK (mode) ~= 0 then return "link" elseif S_ISDIR (mode) ~= 0 then return "directory" elseif S_ISCHR (mode) ~= 0 then return "character device" elseif S_ISBLK (mode) ~= 0 then return "block device" elseif S_ISFIFO (mode) ~= 0 then return "fifo" elseif S_ISSOCK (mode) ~= 0 then return "socket" else return "?" end end local _stat = st.lstat -- for bugwards compatibility with v<=32 local function stat (path, ...) local info = _stat (path) if info ~= nil then return doselection ("stat", 1, {...}, { dev = info.st_dev, ino = info.st_ino, mode = pushmode (info.st_mode), nlink = info.st_nlink, uid = info.st_uid, gid = info.st_gid, size = info.st_size, atime = info.st_atime, mtime = info.st_mtime, ctime = info.st_ctime, type = filetype (info.st_mode), }) end end if _DEBUG ~= false then M.stat = function (path, ...) checkstring ("stat", 1, path, 2) checkselection ("stat", 2, {...}, 2) return stat (path, ...) end else M.stat = stat end --- Fetch file system statistics. -- @function statvfs -- @string path any path within the mounted file system -- @tparam[opt] table|string field one of "bsize", "frsize", "blocks", -- "bfree", "bavail", "files", "ffree", "favail", "fsid", "flag", -- "namemax" -- @string[opt] ... unless *field* was a table, zero or more additional -- field names -- @return values, or table of all fields if no option given -- @see statvfs(2) -- @usage for a,b in pairs (P,statvfs "/") do print (a, b) end local sv = require "posix.sys.statvfs" local _statvfs = sv.statvfs local function statvfs (path, ...) local info = _statvfs (path) if info ~= nil then return doselection ("statvfs", 1, {...}, { bsize = info.f_bsize, frsize = info.f_frsize, blocks = info.f_blocks, bfree = info.f_bfree, bavail = info.f_bavail, files = info.f_files, ffree = info.f_ffree, favail = info.f_favail, fsid = info.f_fsid, flag = info.f_flag, namemax = info.f_namemax, }) end end if _DEBUG ~= false then M.statvfs = function (path, ...) checkstring ("statvfs", 1, path, 2) checkselection ("statvfs", 2, {...}, 2) return statvfs (path, ...) end else M.statvfs = statvfs end --- Write a time out according to a format. -- @function strftime -- @string format specifier with `%` place-holders -- @tparam PosixTm tm broken-down local time -- @treturn string *format* with place-holders plugged with *tm* values -- @see strftime(3) local tm = require "posix.time" local _strftime, localtime, time = tm.strftime, tm.localtime, tm.time local function strftime (fmt, legacytm) local posixtm = legacytm and PosixTm (legacytm) or localtime (time ()) return _strftime (fmt, posixtm) end if _DEBUG ~= false then M.strftime = function (...) local argt = {...} checkstring ("strftime", 1, argt[1]) opttable ("strftime", 2, argt[2]) if #argt > 2 then toomanyargerror ("strftime", 2, #argt) end return strftime (...) end else M.strftime = strftime end --- Parse a date string. -- @function strptime -- @string s -- @string format same as for `strftime` -- @usage posix.strptime('20','%d').monthday == 20 -- @treturn[1] PosixTm broken-down local time -- @treturn[1] int next index of first character not parsed as part of the date -- @return[2] nil -- @see strptime(3) local tm = require "posix.time" local _strptime = tm.strptime local function strptime (s, fmt) return _strptime (s, fmt) end if _DEBUG ~= false then M.strptime = function (...) local argt = {...} checkstring ("strptime", 1, argt[1]) checkstring ("strptime", 2, argt[2]) if #argt > 2 then toomanyargerror ("strptime", 2, #argt) end local tm, i = strptime (...) return LegacyTm (tm), i end else M.strptime = strptime end --- Get configuration information at runtime. -- @function sysconf -- @tparam[opt] table|string key one of "ARG_MAX", "CHILD_MAX", -- "CLK_TCK", "JOB_CONTROL", "NGROUPS_MAX", "OPEN_MAX", "SAVED_IDS", -- "STREAM_MAX", "TZNAME_MAX" or "VERSION" -- @string[opt] ... unless *type* was a table, zero or more additional -- type strings -- @return ... values, or a table of all fields if no option given -- @see sysconf(2) -- @usage for a,b in pairs (P.sysconf ()) do print (a, b) end -- @usage print (P.sysconf ("STREAM_MAX", "ARG_MAX")) local unistd = require "posix.unistd" local _sysconf = unistd.sysconf local function sysconf (...) return doselection ("sysconf", 0, {...}, { ARG_MAX = _sysconf (unistd._SC_ARG_MAX), CHILD_MAX = _sysconf (unistd._SC_CHILD_MAX), CLK_TCK = _sysconf (unistd._SC_CLK_TCK), JOB_CONTROL = _sysconf (unistd._SC_JOB_CONTROL), NGROUPS_MAX = _sysconf (unistd._SC_NGROUPS_MAX), OPEN_MAX = _sysconf (unistd._SC_OPEN_MAX), SAVED_IDS = _sysconf (unistd._SC_SAVED_IDS), STREAM_MAX = _sysconf (unistd._SC_STREAM_MAX), TZNAME_MAX = _sysconf (unistd._SC_TZNAME_MAX), VERSION = _sysconf (unistd._SC_VERSION), }) end if _DEBUG ~= false then M.sysconf = function (...) checkselection ("sysconf", 1, {...}, 2) return sysconf (...) end else M.sysconf = sysconf end --- Get the current process times. -- @function times -- @tparam[opt] table|string key one of "utime", "stime", "cutime", -- "cstime" or "elapsed" -- @string[opt] ... unless *key* was a table, zero or more additional -- key strings. -- @return values, or a table of all fields if no keys given -- @see times(2) -- @usage for a,b in pairs(P.times ()) do print (a, b) end -- @usage print (P.times ("utime", "elapsed") local tms = require "posix.sys.times" local _times = tms.times local function times (...) local info = _times () return doselection ("times", 0, {...}, { utime = info.tms_utime, stime = info.tms_stime, cutime = info.tms_cutime, cstime = info.tms_cstime, elapsed = info.elapsed, }) end if _DEBUG ~= false then M.times = function (...) checkselection ("times", 1, {...}, 2) return times (...) end else M.times = times end --- Return information about this machine. -- @function uname -- @see uname(2) -- @string[opt="%s %n %r %v %m"] format contains zero or more of: -- -- * %m machine name -- * %n node name -- * %r release -- * %s sys name -- * %v version -- --@treturn[1] string filled *format* string, if successful --@return[2] nil --@treturn string error message local utsname = require "posix.sys.utsname" local _uname = utsname.uname local function uname (spec) local u = _uname () return optstring ("uname", 1, spec, "%s %n %r %v %m"):gsub ("%%(.)", function (s) if s == "%" then return "%" elseif s == "m" then return u.machine elseif s == "n" then return u.nodename elseif s == "r" then return u.release elseif s == "s" then return u.sysname elseif s == "v" then return u.version else badoption ("uname", 1, "format", s) end end) end if _DEBUG ~= false then M.uname = function (s, ...) local argt = {s, ...} if #argt > 1 then toomanyargerror ("uname", 1, #argt) end return uname (s) end else M.uname = uname end return M