Blame lib/posix/compat.lua

Packit 437b5e
--[[
Packit 437b5e
 POSIX library for Lua 5.1, 5.2 & 5.3.
Packit 437b5e
 (c) Gary V. Vaughan <gary@vaughan.pe>, 2014-2015
Packit 437b5e
]]
Packit 437b5e
--[[--
Packit 437b5e
 Legacy Lua POSIX bindings.
Packit 437b5e
Packit 437b5e
 APIs for maintaining compatibility with previous releases.
Packit 437b5e
Packit 437b5e
 @module posix
Packit 437b5e
]]
Packit 437b5e
Packit 437b5e
local _argcheck = require "posix._argcheck"
Packit 437b5e
local bit       = require "bit32"
Packit 437b5e
Packit 437b5e
local argerror, argtypeerror, badoption =
Packit 437b5e
  _argcheck.argerror, _argcheck.argtypeerror, _argcheck.badoption
Packit 437b5e
local band, bnot, bor = bit.band, bit.bnot, bit.bor
Packit 437b5e
local checkint, checkselection, checkstring, checktable =
Packit 437b5e
  _argcheck.checkint, _argcheck.checkselection, _argcheck.checkstring, _argcheck.checktable
Packit 437b5e
local optint, optstring, opttable =
Packit 437b5e
  _argcheck.optint, _argcheck.optstring, _argcheck.opttable
Packit 437b5e
local toomanyargerror = _argcheck.toomanyargerror
Packit 437b5e
Packit 437b5e
Packit 437b5e
local st = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local S_IRUSR, S_IWUSR, S_IXUSR = st.S_IRUSR, st.S_IWUSR, st.S_IXUSR
Packit 437b5e
local S_IRGRP, S_IWGRP, S_IXGRP = st.S_IRGRP, st.S_IWGRP, st.S_IXGRP
Packit 437b5e
local S_IROTH, S_IWOTH, S_IXOTH = st.S_IROTH, st.S_IWOTH, st.S_IXOTH
Packit 437b5e
local S_ISUID, S_ISGID, S_IRWXU, S_IRWXG, S_IRWXO =
Packit 437b5e
  st.S_ISUID, st.S_ISGID, st.S_IRWXU, st.S_IRWXG, st.S_IRWXO
Packit 437b5e
Packit 437b5e
local mode_map = {
Packit 437b5e
  { c = "r", b = S_IRUSR }, { c = "w", b = S_IWUSR }, { c = "x", b = S_IXUSR },
Packit 437b5e
  { c = "r", b = S_IRGRP }, { c = "w", b = S_IWGRP }, { c = "x", b = S_IXGRP },
Packit 437b5e
  { c = "r", b = S_IROTH }, { c = "w", b = S_IWOTH }, { c = "x", b = S_IXOTH },
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
local function pushmode (mode)
Packit 437b5e
  local m = {}
Packit 437b5e
  for i = 1, 9 do
Packit 437b5e
    if band (mode, mode_map[i].b) ~= 0 then m[i] = mode_map[i].c else m[i] = "-" end
Packit 437b5e
  end
Packit 437b5e
  if band (mode, S_ISUID) ~= 0 then
Packit 437b5e
    if band (mode, S_IXUSR) ~= 0 then m[3] = "s" else m[3] = "S" end
Packit 437b5e
  end
Packit 437b5e
  if band (mode, S_ISGID) ~= 0 then
Packit 437b5e
    if band (mode, S_IXGRP) ~= 0 then m[6] = "s" else m[6] = "S" end
Packit 437b5e
  end
Packit 437b5e
  return table.concat (m)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
local function rwxrwxrwx (modestr)
Packit 437b5e
  local mode = 0
Packit 437b5e
  for i = 1, 9 do
Packit 437b5e
    if modestr:sub (i, i) == mode_map[i].c then
Packit 437b5e
      mode = bor (mode, mode_map[i].b)
Packit 437b5e
    elseif modestr:sub (i, i) == "s" then
Packit 437b5e
      if i == 3 then
Packit 437b5e
        mode = bor (mode, S_ISUID, S_IXUSR)
Packit 437b5e
      elseif i == 6 then
Packit 437b5e
        mode = bor (mode, S_ISGID, S_IXGRP)
Packit 437b5e
      else
Packit 437b5e
	return nil  -- bad mode
Packit 437b5e
      end
Packit 437b5e
    end
Packit 437b5e
  end
Packit 437b5e
  return mode
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
local function octal_mode (modestr)
Packit 437b5e
  local mode = 0
Packit 437b5e
  for i = 1, #modestr do
Packit 437b5e
    mode = mode * 8 + tonumber (modestr:sub (i, i))
Packit 437b5e
  end
Packit 437b5e
  return mode
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
local function mode_munch (mode, modestr)
Packit 437b5e
  if #modestr == 9 and modestr:match "^[-rswx]+$" then
Packit 437b5e
    return rwxrwxrwx (modestr)
Packit 437b5e
  elseif modestr:match "^[0-7]+$" then
Packit 437b5e
    return octal_mode (modestr)
Packit 437b5e
  elseif modestr:match "^[ugoa]+%s*[-+=]%s*[rswx]+,*" then
Packit 437b5e
    modestr:gsub ("%s*(%a+)%s*(.)%s*(%a+),*", function (who, op, what)
Packit 437b5e
      local bits, bobs = 0, 0
Packit 437b5e
      if who:match "[ua]" then bits = bor (bits, S_ISUID, S_IRWXU) end
Packit 437b5e
      if who:match "[ga]" then bits = bor (bits, S_ISGID, S_IRWXG) end
Packit 437b5e
      if who:match "[oa]" then bits = bor (bits, S_IRWXO) end
Packit 437b5e
      if what:match "r" then bobs = bor (bobs, S_IRUSR, S_IRGRP, S_IROTH) end
Packit 437b5e
      if what:match "w" then bobs = bor (bobs, S_IWUSR, S_IWGRP, S_IWOTH) end
Packit 437b5e
      if what:match "x" then bobs = bor (bobs, S_IXUSR, S_IXGRP, S_IXOTH) end
Packit 437b5e
      if what:match "s" then bobs = bor (bobs, S_ISUID, S_ISGID) end
Packit 437b5e
      if op == "+" then
Packit 437b5e
	-- mode |= bits & bobs
Packit 437b5e
	mode = bor (mode, band (bits, bobs))
Packit 437b5e
      elseif op == "-" then
Packit 437b5e
	-- mode &= ~(bits & bobs)
Packit 437b5e
	mode = band (mode, bnot (band (bits, bobs)))
Packit 437b5e
      elseif op == "=" then
Packit 437b5e
	-- mode = (mode & ~bits) | (bits & bobs)
Packit 437b5e
	mode = bor (band (mode, bnot (bits)), band (bits, bobs))
Packit 437b5e
      end
Packit 437b5e
    end)
Packit 437b5e
    return mode
Packit 437b5e
  else
Packit 437b5e
    return nil, "bad mode"
Packit 437b5e
  end
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
local M = {
Packit 437b5e
  argerror        = argerror,
Packit 437b5e
  argtypeerror    = argtypeerror,
Packit 437b5e
  badoption       = badoption,
Packit 437b5e
  checkstring     = checkstring,
Packit 437b5e
  checktable      = checktable,
Packit 437b5e
  optstring       = optstring,
Packit 437b5e
  toomanyargerror = toomanyargerror,
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Change the mode of the path.
Packit 437b5e
-- @function chmod
Packit 437b5e
-- @string path existing file path
Packit 437b5e
-- @string mode one of the following formats:
Packit 437b5e
--
Packit 437b5e
--   * "rwxrwxrwx" (e.g. "rw-rw-r--")
Packit 437b5e
--   * "ugo+-=rwx" (e.g. "u+w")
Packit 437b5e
--   * +-=rwx" (e.g. "+w")
Packit 437b5e
--
Packit 437b5e
-- @return[1] int `0`, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
-- @see chmod(2)
Packit 437b5e
-- @usage P.chmod ('bin/dof', '+x')
Packit 437b5e
Packit 437b5e
local bit   = require "bit32"
Packit 437b5e
local st    = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local _chmod, stat = st.chmod, st.stat
Packit 437b5e
local RWXALL = bit.bor (st.S_IRWXU, st.S_IRWXG, st.S_IRWXO)
Packit 437b5e
Packit 437b5e
local function chmod (path, modestr)
Packit 437b5e
  local mode = (stat (path) or {}).st_mode
Packit 437b5e
  local bits, err = mode_munch (mode or 0, modestr)
Packit 437b5e
  if bits == nil then
Packit 437b5e
    argerror ("chmod", 2, err, 2)
Packit 437b5e
  end
Packit 437b5e
  return _chmod (path, band (bits, RWXALL))
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.chmod = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checkstring ("chmod", 1, argt[1])
Packit 437b5e
    checkstring ("chmod", 2, argt[2])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("chmod", 2, #argt) end
Packit 437b5e
    return chmod (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.chmod = chmod
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Create a file.
Packit 437b5e
-- This function is obsoleted by @{posix.fcntl.open} with `posix.O_CREAT`.
Packit 437b5e
-- @function creat
Packit 437b5e
-- @string path name of file to create
Packit 437b5e
-- @string mode permissions with which to create file
Packit 437b5e
-- @treturn[1] int file descriptor of file at *path*, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
-- @see creat(2)
Packit 437b5e
-- @see posix.chmod
Packit 437b5e
-- @usage
Packit 437b5e
--   fd = P.creat ("data", "rw-r-----")
Packit 437b5e
Packit 437b5e
local bit   = require "bit32"
Packit 437b5e
local fcntl = require "posix.fcntl"
Packit 437b5e
local st    = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local band, bor   = bit.band, bit.bor
Packit 437b5e
local creat_flags = bor (fcntl.O_CREAT, fcntl.O_WRONLY, fcntl.O_TRUNC)
Packit 437b5e
local RWXALL      = bor (st.S_IRWXU, st.S_IRWXG, st.S_IRWXO)
Packit 437b5e
Packit 437b5e
local open = fcntl.open
Packit 437b5e
Packit 437b5e
local function creat (path, modestr)
Packit 437b5e
  local mode, err = mode_munch (0, modestr)
Packit 437b5e
  if mode == nil then
Packit 437b5e
    argerror ("creat", 2, err, 2)
Packit 437b5e
  end
Packit 437b5e
  return open (path, creat_flags, band (mode, RWXALL))
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.creat = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checkstring ("creat", 1, argt[1])
Packit 437b5e
    checkstring ("creat", 2, argt[2])
Packit 437b5e
    if #argt > 2 then toomanyargerror ("creat", 2, #argt) end
Packit 437b5e
    return creat (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.creat = creat
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Make a directory.
Packit 437b5e
-- @function mkdir
Packit 437b5e
-- @string path location in file system to create directory
Packit 437b5e
-- @treturn[1] int `0`, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
Packit 437b5e
local bit = require "bit32"
Packit 437b5e
local st  = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local _mkdir = st.mkdir
Packit 437b5e
local RWXALL = bit.bor (st.S_IRWXU, st.S_IRWXG, st.S_IRWXO)
Packit 437b5e
Packit 437b5e
local function mkdir (path)
Packit 437b5e
  return _mkdir (path, RWXALL)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.mkdir = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checkstring ("mkdir", 1, argt[1])
Packit 437b5e
    if #argt > 1 then toomanyargerror ("mkdir", 1, #argt) end
Packit 437b5e
    return mkdir (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.mkdir = mkdir
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Make a FIFO pipe.
Packit 437b5e
-- @function mkfifo
Packit 437b5e
-- @string path location in file system to create fifo
Packit 437b5e
-- @treturn[1] int `0`, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
Packit 437b5e
local bit = require "bit32"
Packit 437b5e
local st  = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local _mkfifo = st.mkfifo
Packit 437b5e
local RWXALL  = bit.bor (st.S_IRWXU, st.S_IRWXG, st.S_IRWXO)
Packit 437b5e
Packit 437b5e
local function mkfifo (path)
Packit 437b5e
  return _mkfifo (path, RWXALL)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.mkfifo = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checkstring ("mkfifo", 1, argt[1])
Packit 437b5e
    if #argt > 1 then toomanyargerror ("mkfifo", 1, #argt) end
Packit 437b5e
    return mkfifo (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.mkfifo = mkfifo
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Get a message queue identifier
Packit 437b5e
-- @function msgget
Packit 437b5e
-- @int key message queue id, or `IPC_PRIVATE` for a new queue
Packit 437b5e
-- @int[opt=0] flags bitwise OR of zero or more from `IPC_CREAT` and `IPC_EXCL`
Packit 437b5e
-- @string[opt="rw-rw-rw-"] mode execute bits are ignored
Packit 437b5e
-- @treturn[1] int message queue identifier, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
-- @see msgget(2)
Packit 437b5e
Packit 437b5e
local bit   = require "bit32"
Packit 437b5e
local msg   = require "posix.sys.msg"
Packit 437b5e
local st    = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local _msgget   = msg.msgget
Packit 437b5e
local band, bor = bit.band, bit.bor
Packit 437b5e
local RWXALL    = bor (st.S_IRWXU, st.S_IRWXG, st.S_IRWXO)
Packit 437b5e
Packit 437b5e
local function msgget (key, msgflg, modestr)
Packit 437b5e
  local mode, err = mode_munch (0, modestr)
Packit 437b5e
  if mode == nil then
Packit 437b5e
    argerror ("open", 3, err, 2)
Packit 437b5e
  end
Packit 437b5e
  return _msgget (key, bor (msgflg, band (mode, RWXALL)))
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if not _msgget then
Packit 437b5e
  -- Not supported by underlying system
Packit 437b5e
elseif _DEBUG ~= false then
Packit 437b5e
  M.msgget = function (...)
Packit 437b5e
    local argt = {...}
Packit 437b5e
    checkint ("msgget", 1, argt[1])
Packit 437b5e
    if argt[2] ~= nil and type (argt[2]) ~= "number" then
Packit 437b5e
      argtypeerror ("msgget", 2, "int or nil", argt[2])
Packit 437b5e
    end
Packit 437b5e
    if argt[3] ~= nil and type (argt[3]) ~= "string" then
Packit 437b5e
      argtypeerror ("msgget", 3, "string or nil", argt[3])
Packit 437b5e
    end
Packit 437b5e
    if #argt > 3 then toomanyargerror ("msgget", 3, #argt) end
Packit 437b5e
    return msgget (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.msgget = msgget
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Open a file.
Packit 437b5e
-- @function open
Packit 437b5e
-- @string path file to act on
Packit 437b5e
-- @int oflags bitwise OR of zero or more of `O_RDONLY`, `O_WRONLY`, `O_RDWR`,
Packit 437b5e
--   `O_APPEND`, `O_CREAT`, `O_DSYNC`, `O_EXCL`, `O_NOCTTY`, `O_NONBLOCK`,
Packit 437b5e
--   `O_RSYNC`, `O_SYNC`, `O_TRUNC`
Packit 437b5e
-- @string modestr (used with `O_CREAT`; see @{chmod} for format)
Packit 437b5e
-- @treturn[1] int file descriptor for *path*, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
-- @see open(2)
Packit 437b5e
-- @usage
Packit 437b5e
-- fd = P.open ("data", bit.bor (P.O_CREAT, P.O_RDWR), "rw-r-----")
Packit 437b5e
Packit 437b5e
local bit   = require "bit32"
Packit 437b5e
local fcntl = require "posix.fcntl"
Packit 437b5e
Packit 437b5e
local _open, O_CREAT = fcntl.open, fcntl.O_CREAT
Packit 437b5e
local band = bit.band
Packit 437b5e
Packit 437b5e
local function open (path, oflags, modestr)
Packit 437b5e
  local mode
Packit 437b5e
  if band (oflags, O_CREAT) ~= 0 then
Packit 437b5e
    mode, err = mode_munch (0, modestr)
Packit 437b5e
    if mode == nil then
Packit 437b5e
      argerror ("open", 3, err, 2)
Packit 437b5e
    end
Packit 437b5e
    mode = band (mode, RWXALL)
Packit 437b5e
  end
Packit 437b5e
  return _open (path, oflags, mode)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.open = function (...)
Packit 437b5e
    local argt, maxt = {...}, 2
Packit 437b5e
    checkstring ("open", 1, argt[1])
Packit 437b5e
    local oflags = checkint ("open", 2, argt[2])
Packit 437b5e
    if band (oflags, O_CREAT) ~= 0 then
Packit 437b5e
      checkstring ("open", 3, argt[3])
Packit 437b5e
      maxt = 3
Packit 437b5e
    end
Packit 437b5e
    if #argt > maxt then toomanyargerror ("open", maxt, #argt) end
Packit 437b5e
    return open (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.creat = creat
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Set log priority mask
Packit 437b5e
-- @function setlogmask
Packit 437b5e
-- @int ... zero or more of `LOG_EMERG`, `LOG_ALERT`, `LOG_CRIT`,
Packit 437b5e
--   `LOG_WARNING`, `LOG_NOTICE`, `LOG_INFO` and `LOG_DEBUG`
Packit 437b5e
-- @treturn[1] int `0`, if successful
Packit 437b5e
-- @return[2] nil
Packit 437b5e
-- @treturn[2] string error message
Packit 437b5e
-- @treturn[2] int errnum
Packit 437b5e
Packit 437b5e
local bit = require "bit32"
Packit 437b5e
local log = require "posix.syslog"
Packit 437b5e
Packit 437b5e
local bor = bit.bor
Packit 437b5e
local _setlogmask, LOG_MASK = log.setlogmask, log.LOG_MASK
Packit 437b5e
Packit 437b5e
local function setlogmask (...)
Packit 437b5e
  local mask = 0
Packit 437b5e
  for _, v in ipairs {...} do
Packit 437b5e
    mask = bor (mask, LOG_MASK (v))
Packit 437b5e
  end
Packit 437b5e
  return _setlogmask (mask)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.setlogmask = function (...)
Packit 437b5e
    for i, v in ipairs {...} do
Packit 437b5e
      optint ("setlogmask", i, v, 0) -- for "int or nil" error
Packit 437b5e
    end
Packit 437b5e
    return setlogmask (...)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.setlogmask = setlogmask
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
--- Set file mode creation mask.
Packit 437b5e
-- @function umask
Packit 437b5e
-- @string[opt] mode file creation mask string
Packit 437b5e
-- @treturn string previous umask
Packit 437b5e
-- @see umask(2)
Packit 437b5e
-- @see posix.sys.stat.umask
Packit 437b5e
Packit 437b5e
local st = require "posix.sys.stat"
Packit 437b5e
Packit 437b5e
local _umask, RWXALL = st.umask, bor (st.S_IRWXU, st.S_IRWXG, st.S_IRWXO)
Packit 437b5e
Packit 437b5e
local function umask (modestr)
Packit 437b5e
  modestr = modestr or ""
Packit 437b5e
  local mode = _umask (0)
Packit 437b5e
  _umask (mode)
Packit 437b5e
  mode = band (bnot (mode), RWXALL)
Packit 437b5e
  if #modestr > 0 then
Packit 437b5e
    local bits, err = mode_munch (mode, modestr)
Packit 437b5e
    if bits == nil then
Packit 437b5e
      argerror ("umask", 1, err, 2)
Packit 437b5e
    end
Packit 437b5e
    mode = band (bits, RWXALL)
Packit 437b5e
    _umask (bnot (mode))
Packit 437b5e
  end
Packit 437b5e
  return pushmode (mode)
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
if _DEBUG ~= false then
Packit 437b5e
  M.umask = function (modestr, ...)
Packit 437b5e
    local argt = {modestr, ...}
Packit 437b5e
    optstring ("umask", 1, modestr, "")
Packit 437b5e
    if #argt > 1 then
Packit 437b5e
      toomanyargerror ("umask", 1, #argt)
Packit 437b5e
    end
Packit 437b5e
    return umask (modestr)
Packit 437b5e
  end
Packit 437b5e
else
Packit 437b5e
  M.umask = umask
Packit 437b5e
end
Packit 437b5e
Packit 437b5e
Packit 437b5e
return M