/usr/share/lua/5.1/syscall/util.lua is in lua-ljsyscall 0.12-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | -- generic utils not specific to any OS
-- these are generally equivalent to things that are in man(1) or man(3)
-- these can be made more modular as number increases
local require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string =
require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string
local function init(S)
local h = require "syscall.helpers"
local htonl = h.htonl
local ffi = require "ffi"
local bit = require "syscall.bit"
local abi, types, c = S.abi, S.types, S.c
local t, pt, s = types.t, types.pt, types.s
local mt, meth = {}, {}
local util = require("syscall." .. abi.os .. ".util").init(S)
mt.dir = {
__tostring = function(t)
if #t == 0 then return "" end
table.sort(t)
return table.concat(t, "\n") .. "\n"
end
}
function util.dirtable(name, nodots) -- return table of directory entries, remove . and .. if nodots true
local d = {}
local size = 4096
local buf = t.buffer(size)
local iter, err = util.ls(name, buf, size)
if not iter then return nil, err end
for f in iter do
if not (nodots and (f == "." or f == "..")) then d[#d + 1] = f end
end
return setmetatable(d, mt.dir)
end
-- this returns an iterator over multiple calls to getdents TODO add nodots?
-- note how errors work, getdents will throw as called multiple times, but normally should not fail if open succeeds
-- getdents can fail eg on nfs though.
function util.ls(name, buf, size)
size = size or 4096
buf = buf or t.buffer(size)
if not name then name = "." end
local fd, err = S.open(name, "directory, rdonly")
if err then return nil, err end
local di
return function()
local d, first
repeat
if not di then
local err
di, err = fd:getdents(buf, size)
if not di then
fd:close()
error(err)
end
first = true
end
d = di()
if not d then di = nil end
if not d and first then return nil end
until d
return d.name, d
end
end
-- recursive rm TODO use ls iterator, which also returns type
local function rmhelper(file, prefix)
local name
if prefix then name = prefix .. "/" .. file else name = file end
local st, err = S.lstat(name)
if not st then return nil, err end
if st.isdir then
local files, err = util.dirtable(name, true)
if not files then return nil, err end
for _, f in pairs(files) do
local ok, err = rmhelper(f, name)
if not ok then return nil, err end
end
local ok, err = S.rmdir(name)
if not ok then return nil, err end
else
local ok, err = S.unlink(name)
if not ok then return nil, err end
end
return true
end
function util.rm(...)
for _, f in ipairs{...} do
local ok, err = rmhelper(f)
if not ok then return nil, err end
end
return true
end
-- TODO warning broken
function util.cp(source, dest, mode) -- TODO make much more functional, less broken, esp fix mode! and size issue!!
local contents, err = util.readfile(source)
if not contents then return nil, err end
local ok, err = util.writefile(dest, contents, mode)
if not ok then return nil, err end
return true
end
function util.touch(file)
local fd, err = S.open(file, "wronly,creat,noctty,nonblock", "0666")
if not fd then return nil, err end
local fd2, err = S.dup(fd)
if not fd2 then
fd2:close()
return nil, err
end
fd:close()
local ok, err = S.futimes(fd2)
fd2:close()
if not ok then return nil, err end
return true
end
function util.createfile(file) -- touch without timestamp adjustment
local fd, err = S.open(file, "wronly,creat,noctty,nonblock", "0666")
if not fd then return nil, err end
local ok, err = fd:close()
if not ok then return nil, err end
return true
end
function util.mapfile(name) -- generally better to use, but no good for sysfs etc
local fd, err = S.open(name, "rdonly")
if not fd then return nil, err end
local st, err = S.fstat(fd)
if not st then return nil, err end
local size = st.size
local m, err = S.mmap(nil, size, "read", "shared", fd, 0)
if not m then return nil, err end
local str = ffi.string(m, size)
local ok, err = S.munmap(m, size)
if not ok then return nil, err end
local ok, err = fd:close()
if not ok then return nil, err end
return str
end
-- TODO fix short reads, but mainly used for sysfs, proc
function util.readfile(name, buffer, length)
local fd, err = S.open(name, "rdonly")
if not fd then return nil, err end
local r, err = S.read(fd, buffer, length or 4096)
if not r then return nil, err end
local ok, err = fd:close()
if not ok then return nil, err end
return r
end
-- write string to named file; silently ignore short writes TODO fix
function util.writefile(name, str, mode, flags)
local fd, err
if mode then fd, err = S.creat(name, mode) else fd, err = S.open(name, flags or "wronly") end
if not fd then return nil, err end
local n, err = S.write(fd, str)
if not n then return nil, err end
local ok, err = fd:close()
if not ok then return nil, err end
return true
end
mt.ps = {
__tostring = function(ps)
local s = {}
for i = 1, #ps do
s[#s + 1] = tostring(ps[i])
end
return table.concat(s, '\n')
end
}
-- note that Linux and NetBSD have /proc but FreeBSD does not usually have it mounted, although it is an option
function util.ps()
local ls, err = util.dirtable("/proc")
if not ls then return nil, err end
local ps = {}
for i = 1, #ls do
if not string.match(ls[i], '[^%d]') then
local p = util.proc(tonumber(ls[i]))
if p then ps[#ps + 1] = p end
end
end
table.sort(ps, function(a, b) return a.pid < b.pid end)
return setmetatable(ps, mt.ps)
end
mt.proc = {
__index = function(p, k)
local name = p.dir .. k
local st, err = S.lstat(name)
if not st then return nil, err end
if st.isreg then
local fd, err = S.open(p.dir .. k, "rdonly")
if not fd then return nil, err end
local ret, err = S.read(fd) -- read defaults to 4k, sufficient?
if not ret then return nil, err end
S.close(fd)
return ret -- TODO many could usefully do with some parsing
end
if st.islnk then
local ret, err = S.readlink(name)
if not ret then return nil, err end
return ret
end
-- TODO directories
end,
__tostring = function(p) -- TODO decide what to print
local c = p.cmdline
if c then
if #c == 0 then
local comm = p.comm
if comm and #comm > 0 then
c = '[' .. comm:sub(1, -2) .. ']'
end
end
return p.pid .. ' ' .. c
end
end
}
function util.proc(pid)
if not pid then pid = S.getpid() end
return setmetatable({pid = pid, dir = "/proc/" .. pid .. "/"}, mt.proc)
end
-- receive cmsg, extended helper on recvmsg, fairly incomplete at present
function util.recvcmsg(fd, msg, flags)
if not msg then
local buf1 = t.buffer(1) -- assume user wants to receive single byte to get cmsg
local io = t.iovecs{{buf1, 1}}
local bufsize = 1024 -- sane default, build your own structure otherwise
local buf = t.buffer(bufsize)
msg = t.msghdr{iov = io, msg_control = buf, msg_controllen = bufsize}
end
local count, err = S.recvmsg(fd, msg, flags)
if not count then return nil, err end
local ret = {count = count, iovec = msg.msg_iov} -- thats the basic return value, and the iovec
for mc, cmsg in msg:cmsgs() do
local pid, uid, gid = cmsg:credentials()
if pid then
ret.pid = pid
ret.uid = uid
ret.gid = gid
end
local fd_array = {}
for fd in cmsg:fds() do
fd_array[#fd_array + 1] = fd
end
ret.fd = fd_array
end
return ret
end
function util.sendfds(fd, ...)
local buf1 = t.buffer(1) -- need to send one byte
local io = t.iovecs{{buf1, 1}}
local cmsg = t.cmsghdr("socket", "rights", {...})
local msg = t.msghdr{iov = io, control = cmsg}
return S.sendmsg(fd, msg, 0)
end
-- generic inet name to ip, also with netmask support
-- TODO convert to a type? either way should not really be in util, probably helpers
-- better as a type that returns inet, mask
function util.inet_name(src, netmask)
local addr
if not netmask then
local a, b = src:find("/", 1, true)
if a then
netmask = tonumber(src:sub(b + 1))
src = src:sub(1, a - 1)
end
end
if src:find(":", 1, true) then -- ipv6
addr = t.in6_addr(src)
if not addr then return nil end
if not netmask then netmask = 128 end
else
addr = t.in_addr(src)
if not addr then return nil end
if not netmask then netmask = 32 end
end
return addr, netmask
end
local function lastslash(name)
local ls
local i = 0
while true do
i = string.find(name, "/", i + 1)
if not i then return ls end
ls = i
end
end
local function deltrailslash(name)
while name:sub(#name) == "/" do
name = string.sub(name, 1, #name - 1)
end
return name
end
function util.basename(name)
if name == "" then return "." end
name = deltrailslash(name)
if name == "" then return "/" end -- was / or // etc
local ls = lastslash(name)
if not ls then return name end
return string.sub(name, ls + 1)
end
function util.dirname(name)
if name == "" then return "." end
name = deltrailslash(name)
if name == "" then return "/" end -- was / or // etc
local ls = lastslash(name)
if not ls then return "." end
name = string.sub(name, 1, ls - 1)
name = deltrailslash(name)
if name == "" then return "/" end -- was / or // etc
return name
end
return util
end
return {init = init}
|