Blame lib/posix/init.lua

Packit 437b5e
--[[
Packit 437b5e
 POSIX library for Lua 5.1, 5.2 & 5.3.
Packit 437b5e
 (c) Gary V. Vaughan <gary@vaughan.pe>, 2013-2015
Packit 437b5e
 (c) Reuben Thomas <rrt@sc3d.org> 2010-2015
Packit 437b5e
 (c) Natanael Copa <natanael.copa@gmail.com> 2008-2010
Packit 437b5e
]]
Packit 437b5e
--[[--
Packit 437b5e
 Lua POSIX bindings.
Packit 437b5e
Packit 437b5e
 In addition to the convenience functions documented in this module, all
Packit 437b5e
 APIs from submodules are copied into the return table for convenience and
Packit 437b5e
 backwards compatibility.
Packit 437b5e
Packit 437b5e
 @module posix
Packit 437b5e
]]
Packit 437b5e
Packit 437b5e
local bit = require "bit32"
Packit 437b5e
local M = {}
Packit 437b5e
Packit 437b5e
Packit 437b5e
-- For backwards compatibility, copy all table entries into M namespace.
Packit 437b5e
for _, sub in ipairs {
Packit 437b5e
  "ctype", "dirent", "errno", "fcntl", "fnmatch", "getopt", "glob", "grp",
Packit 437b5e
  "libgen", "poll", "pwd", "sched", "signal", "stdio", "stdlib", "sys.msg",
Packit 437b5e
  "sys.resource", "sys.socket", "sys.stat", "sys.statvfs", "sys.time",
Packit 437b5e
  "sys.times", "sys.utsname", "sys.wait", "syslog", "termio", "time",
Packit 437b5e
  "unistd", "utime"
Packit 437b5e
} do
Packit 437b5e
  local t = require ("posix." .. sub)
Packit 437b5e
  for k, v in pairs (t) do
Packit 437b5e
    if k ~= "version" then
Packit 437b5e
      assert(M[k] == nil, "posix namespace clash: " .. sub .. "." .. k)
Packit 437b5e
      M[k] = v
Packit 437b5e
    end
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
-- Inject deprecated APIs (overwriting submodules) for backwards compatibility.
Packit 437b5e
for k, v in pairs (require "posix.deprecated") do
Packit 437b5e
  M[k] = v
Packit 437b5e
end
Packit 437b5e
for k, v in pairs (require "posix.compat") do
Packit 437b5e
  M[k] = v
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
M.version = "posix for " .. _VERSION .. " / luaposix 33.3.1"
Packit 437b5e
Packit 437b5e
Packit 437b5e
local argerror, argtypeerror, checkstring, checktable, toomanyargerror =
Packit 437b5e
  M.argerror, M.argtypeerror, M.checkstring, M.checktable, M.toomanyargerror
Packit 437b5e
Packit 437b5e
Packit 437b5e
-- Code extracted from lua-stdlib with minimal modifications
Packit 437b5e
local list = {
Packit 437b5e
  sub = function (l, from, to)
Packit 437b5e
    local r = {}
Packit 437b5e
    local len = #l
Packit 437b5e
    from = from or 1
Packit 437b5e
    to = to or len
Packit 437b5e
    if from < 0 then
Packit 437b5e
      from = from + len + 1
Packit 437b5e
    end
Packit 437b5e
    if to < 0 then
Packit 437b5e
      to = to + len + 1
Packit 437b5e
    end
Packit 437b5e
    for i = from, to do
Packit 437b5e
      table.insert (r, l[i])
Packit 437b5e
    end
Packit 437b5e
    return r
Packit 437b5e
  end
Packit 437b5e
}
Packit 437b5e
-- end of stdlib code
Packit 437b5e
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Check permissions like @{posix.unistd.access}, but for euid.
Packit 437b5e
-- Based on the glibc function of the same name. Does not always check
Packit 437b5e
-- for read-only file system, text busy, etc., and does not work with
Packit 437b5e
-- ACLs &c.
Packit 437b5e
-- @function euidaccess
Packit 437b5e
-- @string file file to check
Packit 437b5e
-- @string mode checks to perform (as for access)
Packit 437b5e
-- @return 0 if access allowed; nil otherwise (and errno is set)
Packit 437b5e
Packit 437b5e
local access, set_errno, stat = M.access, M.set_errno, M.stat
Packit 437b5e
local getegid, geteuid, getgid, getuid =
Packit 437b5e
  M.getegid, M.geteuid, M.getgid, M.getuid
Packit 437b5e
Packit 437b5e
local function euidaccess (file, mode)
Packit 437b5e
  local euid, egid = geteuid (), getegid ()
Packit 437b5e
Packit 437b5e
  if getuid () == euid and getgid () == egid then
Packit 437b5e
    -- If we are not set-uid or set-gid, access does the same.
Packit 437b5e
    return access (file, mode)
Packit 437b5e
  end
Packit 437b5e
Packit 437b5e
  local stats = stat (file)
Packit 437b5e
  if not stats then
Packit 437b5e
    return
Packit 437b5e
  end
Packit 437b5e
Packit 437b5e
  -- The super-user can read and write any file, and execute any file
Packit 437b5e
  -- that anyone can execute.
Packit 437b5e
  if euid == 0 and ((not string.match (mode, "x")) or
Packit 437b5e
                    string.match (stats.st_mode, "x")) then
Packit 437b5e
    return 0
Packit 437b5e
  end
Packit 437b5e
Packit 437b5e
  -- Convert to simple list of modes.
Packit 437b5e
  mode = string.gsub (mode, "[^rwx]", "")
Packit 437b5e
Packit 437b5e
  if mode == "" then
Packit 437b5e
    return 0 -- The file exists.
Packit 437b5e
  end
Packit 437b5e
Packit 437b5e
  -- Get the modes we need.
Packit 437b5e
  local granted = stats.st_mode:sub (1, 3)
Packit 437b5e
  if euid == stats.st_uid then
Packit 437b5e
    granted = stats.st_mode:sub (7, 9)
Packit 437b5e
  elseif egid == stats.st_gid or set.new (posix.getgroups ()):member (stats.st_gid) then
Packit 437b5e
    granted = stats.st_mode:sub (4, 6)
Packit 437b5e
  end
Packit 437b5e
  granted = string.gsub (granted, "[^rwx]", "")
Packit 437b5e
Packit 437b5e
  if string.gsub ("[^" .. granted .. "]", mode) == "" then
Packit 437b5e
    return 0
Packit 437b5e
  end
Packit 437b5e
  set_errno (EACCESS)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.euidaccess = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checkstring ("euidaccess", 1, argt[1])
Packit 437b5e
    checkstring ("euidaccess", 2, argt[2])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("euidaccess", 2, #argt) end
Packit 437b5e
    return euidaccess (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.euidaccess = euidaccess
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Open a pseudo-terminal.
Packit 437b5e
-- Based on the glibc function of the same name.
Packit 437b5e
-- @fixme add support for term and win arguments
Packit 437b5e
-- @treturn[1] int master file descriptor
Packit 437b5e
-- @treturn[1] int slave file descriptor
Packit 437b5e
-- @treturn[1] string slave file name
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
Packit 437b5e
local bit    = require "bit32"
Packit 437b5e
local fcntl  = require "posix.fcntl"
Packit 437b5e
local stdlib = require "posix.stdlib"
Packit 437b5e
local unistd = require "posix.unistd"
Packit 437b5e
Packit 437b5e
local bor = bit.bor
Packit 437b5e
local open, O_RDWR, O_NOCTTY = fcntl.open, fcntl.O_RDWR, fcntl.O_NOCTTY
Packit 437b5e
local grantpt, openpt, ptsname, unlockpt =
Packit 437b5e
  stdlib.grantpt, stdlib.openpt, stdlib.ptsname, stdlib.unlockpt
Packit 437b5e
local close = unistd.close
Packit 437b5e
Packit 437b5e
local function openpty (term, win)
Packit 437b5e
  local ok, errmsg, master, slave, slave_name
Packit 437b5e
  master, errmsg = openpt (bor (O_RDWR, O_NOCTTY))
Packit 437b5e
  if master then
Packit 437b5e
    ok, errmsg = grantpt (master)
Packit 437b5e
    if ok then
Packit 437b5e
      ok, errmsg = unlockpt (master)
Packit 437b5e
      if ok then
Packit 437b5e
	slave_name, errmsg = ptsname (master)
Packit 437b5e
	if slave_name then
Packit 437b5e
          slave, errmsg = open (slave_name, bor (O_RDWR, O_NOCTTY))
Packit 437b5e
	  if slave then
Packit 437b5e
            return master, slave, slave_name
Packit 437b5e
	  end
Packit 437b5e
	end
Packit 437b5e
      end
Packit 437b5e
    end
Packit 437b5e
    close (master)
Packit 437b5e
  end
Packit 437b5e
  return nil, errmsg
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.openpty = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    if #argt > 0 then toomanyargerror ("openpty", 0, #argt) end
Packit 437b5e
    return openpty (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.openpty = openpty
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Exec a command or Lua function.
Packit 437b5e
-- @function execx
Packit 437b5e
-- @param task, a table of arguments to `P.execp` or a Lua function, which
Packit 437b5e
--   should read from standard input, write to standard output, and return
Packit 437b5e
--   an exit code
Packit 437b5e
-- @param ... positional arguments to the function
Packit 437b5e
-- @treturn nil on error (normally does not return)
Packit 437b5e
-- @treturn string error message
Packit 437b5e
Packit 437b5e
local unpack = table.unpack or unpack -- 5.3 compatibility
Packit 437b5e
Packit 437b5e
local errno, execp, _exit =
Packit 437b5e
  M.errno, M.execp, M._exit
Packit 437b5e
Packit 437b5e
function execx (task, ...)
Packit 437b5e
  if type (task) == "table" then
Packit 437b5e
    execp (unpack (task))
Packit 437b5e
    -- Only get here if there's an error; kill the fork
Packit 437b5e
    local _, n = errno ()
Packit 437b5e
    _exit (n)
Packit 437b5e
  else
Packit 437b5e
    _exit (task (...) or 0)
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.execx = function (task, ...)
Packit 437b5e
    local argt, typetask = {task, ...}, type (task)
Packit 437b5e
    if typetask ~= "table" and typetask ~= "function" then
Packit 437b5e
      argtypeerror ("execx", 1, "table or function", task)
Packit 437b5e
    end
Packit 437b5e
    return execx (task, ...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.execx = execx
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Run a command or function in a sub-process using `P.execx`.
Packit 437b5e
-- @function spawn
Packit 437b5e
-- @param task, as for `P.execx`.
Packit 437b5e
-- @tparam string ... as for `P.execx`
Packit 437b5e
-- @return values as for `P.wait`
Packit 437b5e
Packit 437b5e
local unpack = table.unpack or unpack -- 5.3 compatibility
Packit 437b5e
Packit 437b5e
local fork, wait =
Packit 437b5e
  M.fork, M.wait
Packit 437b5e
Packit 437b5e
local function spawn (task, ...)
Packit 437b5e
  local pid, err = fork ()
Packit 437b5e
  if pid == nil then
Packit 437b5e
    return pid, err
Packit 437b5e
  elseif pid == 0 then
Packit 437b5e
    execx (task, ...)
Packit 437b5e
  else
Packit 437b5e
    local _, reason, status = wait (pid)
Packit 437b5e
    return status, reason -- If wait failed, status is nil & reason is error
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.spawn = function (task, ...)
Packit 437b5e
    local argt, typetask = {task, ...}, type (task)
Packit 437b5e
    if typetask ~= "table" and typetask ~= "function" then
Packit 437b5e
      argtypeerror ("spawn", 1, "table or function", task)
Packit 437b5e
    end
Packit 437b5e
    return spawn (task, ...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.spawn = spawn
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
local close, dup2, fork, pipe, wait, _exit =
Packit 437b5e
  M.close, M.dup2, M.fork, M.pipe, M.wait, M._exit
Packit 437b5e
local STDIN_FILENO, STDOUT_FILENO = M.STDIN_FILENO, M.STDOUT_FILENO
Packit 437b5e
Packit 437b5e
--- Close a pipeline opened with popen or popen_pipeline.
Packit 437b5e
-- @function pclose
Packit 437b5e
-- @tparam table pfd pipeline object
Packit 437b5e
-- @return values as for `P.wait`, for the last (or only) stage of the pipeline
Packit 437b5e
Packit 437b5e
local function pclose (pfd)
Packit 437b5e
  close (pfd.fd)
Packit 437b5e
  for i = 1, #pfd.pids - 1 do
Packit 437b5e
    wait (pfd.pids[i])
Packit 437b5e
  end
Packit 437b5e
  local _, reason, status = wait (pfd.pids[#pfd.pids])
Packit 437b5e
  return reason, status
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.pclose = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checktable ("pclose", 1, argt[1])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("pclose", 1, #argt) end
Packit 437b5e
    return pclose (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.pclose = pclose
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
local function move_fd (from_fd, to_fd)
Packit 437b5e
  if from_fd ~= to_fd then
Packit 437b5e
    if not dup2 (from_fd, to_fd) then
Packit 437b5e
      error "error dup2-ing"
Packit 437b5e
    end
Packit 437b5e
    close (from_fd)
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
--- Run a commands or Lua function in a sub-process.
Packit 437b5e
-- @function popen
Packit 437b5e
-- @tparam task, as for @{execx}
Packit 437b5e
-- @tparam string mode `"r"` for read or `"w"` for write
Packit 437b5e
-- @func[opt] pipe_fn function returning a paired read and
Packit 437b5e
--   write file descriptor (*default* @{posix.unistd.pipe})
Packit 437b5e
-- @treturn pfd pipeline object
Packit 437b5e
Packit 437b5e
local function popen (task, mode, pipe_fn)
Packit 437b5e
  local read_fd, write_fd = (pipe_fn or pipe) ()
Packit 437b5e
  if not read_fd then
Packit 437b5e
    error "error opening pipe"
Packit 437b5e
  end
Packit 437b5e
  local parent_fd, child_fd, in_fd, out_fd
Packit 437b5e
  if mode == "r" then
Packit 437b5e
    parent_fd, child_fd, in_fd, out_fd = read_fd, write_fd, STDIN_FILENO, STDOUT_FILENO
Packit 437b5e
  elseif mode == "w" then
Packit 437b5e
    parent_fd, child_fd, in_fd, out_fd = write_fd, read_fd, STDOUT_FILENO, STDIN_FILENO
Packit 437b5e
  else
Packit 437b5e
    error "invalid mode"
Packit 437b5e
  end
Packit 437b5e
  local pid = fork ()
Packit 437b5e
  if pid == nil then
Packit 437b5e
    error "error forking"
Packit 437b5e
  elseif pid == 0 then -- child process
Packit 437b5e
    move_fd (child_fd, out_fd)
Packit 437b5e
    close (parent_fd)
Packit 437b5e
    _exit (execx (task, child_fd, in_fd, out_fd))
Packit 437b5e
  end -- parent process
Packit 437b5e
  close (child_fd)
Packit 437b5e
  return {pids = {pid}, fd = parent_fd}
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.popen = function (task, ...)
Packit 437b5e
    local argt, typetask = {task, ...}, type (task)
Packit 437b5e
    if typetask ~= "table" and typetask ~= "function" then
Packit 437b5e
      argtypeerror ("popen", 1, "table or function", task)
Packit 437b5e
    end
Packit 437b5e
    checkstring ("popen", 2, argt[2])
Packit 437b5e
    if argt[3] ~= nil and type (argt[3]) ~= "function" then
Packit 437b5e
      argtypeerror ("popen", 3, "function or nil", argt[3])
Packit 437b5e
    end
Packit 437b5e
    if #argt > 3 then toomanyargerror ("popen", 3, #argt) end
Packit 437b5e
    return popen (task, ...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.popen = popen
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Perform a series of commands and Lua functions as a pipeline.
Packit 437b5e
-- @function popen_pipeline
Packit 437b5e
-- @tparam table t tasks for @{execx}
Packit 437b5e
-- @tparam string mode `"r"` for read or `"w"` for write
Packit 437b5e
-- @func[opt] pipe_fn function returning a paired read and
Packit 437b5e
--   write file descriptor (*default* @{posix.unistd.pipe})
Packit 437b5e
-- @treturn pfd pipeline object
Packit 437b5e
Packit 437b5e
local close, _exit = M.close, M._exit
Packit 437b5e
Packit 437b5e
local function popen_pipeline (tasks, mode, pipe_fn)
Packit 437b5e
  local first, from, to, inc = 1, 2, #tasks, 1
Packit 437b5e
  if mode == "w" then
Packit 437b5e
    first, from, to, inc = #tasks, #tasks - 1, 1, -1
Packit 437b5e
  end
Packit 437b5e
  local pfd = popen (tasks[first], mode, pipe_fn)
Packit 437b5e
  for i = from, to, inc do
Packit 437b5e
    local pfd_next = popen (function (fd, in_fd, out_fd)
Packit 437b5e
                              move_fd (pfd.fd, in_fd)
Packit 437b5e
                              _exit (execx (tasks[i]))
Packit 437b5e
                            end,
Packit 437b5e
                            mode,
Packit 437b5e
                            pipe_fn)
Packit 437b5e
    close (pfd.fd)
Packit 437b5e
    pfd.fd = pfd_next.fd
Packit 437b5e
    table.insert (pfd.pids, pfd_next.pids[1])
Packit 437b5e
  end
Packit 437b5e
  return pfd
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.popen_pipeline = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checktable ("popen_pipeline", 1, argt[1])
Packit 437b5e
    checkstring ("popen_pipeline", 2, argt[2])
Packit 437b5e
    if argt[3] ~= nil and type (argt[3]) ~= "function" then
Packit 437b5e
      argtypeerror ("popen_pipeline", 3, "function or nil", argt[3])
Packit 437b5e
    end
Packit 437b5e
    if #argt > 3 then toomanyargerror ("popen_pipeline", 3, #argt) end
Packit 437b5e
    return popen_pipeline (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.popen_pipeline = popen_pipeline
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Add one gettimeofday() returned timeval to another.
Packit 437b5e
-- @function timeradd
Packit 437b5e
-- @param x a timeval
Packit 437b5e
-- @param y another timeval
Packit 437b5e
-- @return x + y, adjusted for usec overflow
Packit 437b5e
Packit 437b5e
local function timeradd (x, y)
Packit 437b5e
  local sec, usec = 0, 0
Packit 437b5e
  if x.sec then sec = sec + x.sec end
Packit 437b5e
  if y.sec then sec = sec + y.sec end
Packit 437b5e
  if x.usec then usec = usec + x.usec end
Packit 437b5e
  if y.usec then usec = usec + y.usec end
Packit 437b5e
  if usec > 1000000 then
Packit 437b5e
    sec = sec + 1
Packit 437b5e
    usec = usec - 1000000
Packit 437b5e
  end
Packit 437b5e
Packit 437b5e
  return { sec = sec, usec = usec }
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.timeradd = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checktable ("timeradd", 1, argt[1])
Packit 437b5e
    checktable ("timeradd", 2, argt[2])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("timeradd", 2, #argt) end
Packit 437b5e
    return timeradd (...)
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Compare one gettimeofday() returned timeval with another
Packit 437b5e
-- @function timercmp
Packit 437b5e
-- @param x a timeval
Packit 437b5e
-- @param y another timeval
Packit 437b5e
-- @return 0 if x and y are equal, >0 if x is newer, <0 if y is newer
Packit 437b5e
Packit 437b5e
local function timercmp (x, y)
Packit 437b5e
  local x = { sec = x.sec or 0, usec = x.usec or 0 }
Packit 437b5e
  local y = { sec = y.sec or 0, usec = y.usec or 0 }
Packit 437b5e
  if x.sec ~= y.sec then
Packit 437b5e
    return x.sec - y.sec
Packit 437b5e
  else
Packit 437b5e
    return x.usec - y.usec
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.timercmp = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checktable ("timercmp", 1, argt[1])
Packit 437b5e
    checktable ("timercmp", 2, argt[2])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("timercmp", 2, #argt) end
Packit 437b5e
    return timercmp (...)
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Subtract one gettimeofday() returned timeval from another.
Packit 437b5e
-- @function timersub
Packit 437b5e
-- @param x a timeval
Packit 437b5e
-- @param y another timeval
Packit 437b5e
-- @return x - y, adjusted for usec underflow
Packit 437b5e
Packit 437b5e
local function timersub (x,y)
Packit 437b5e
  local sec, usec = 0, 0
Packit 437b5e
  if x.sec then sec = x.sec end
Packit 437b5e
  if y.sec then sec = sec - y.sec end
Packit 437b5e
  if x.usec then usec = x.usec end
Packit 437b5e
  if y.usec then usec = usec - y.usec end
Packit 437b5e
  if usec < 0 then
Packit 437b5e
    sec = sec - 1
Packit 437b5e
    usec = usec + 1000000
Packit 437b5e
  end
Packit 437b5e
  return { sec = sec, usec = usec }
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.timersub = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checktable ("timersub", 1, argt[1])
Packit 437b5e
    checktable ("timersub", 2, argt[2])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("timersub", 2, #argt) end
Packit 437b5e
    return timersub (...)
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
return M