├── syscall ├── linux │ ├── mipsel │ ├── x64 │ │ ├── ioctl.lua │ │ ├── constants.lua │ │ └── ffi.lua │ ├── x86 │ │ ├── ioctl.lua │ │ ├── constants.lua │ │ └── ffi.lua │ ├── arm64 │ │ ├── ioctl.lua │ │ ├── constants.lua │ │ └── ffi.lua │ ├── arm │ │ ├── ioctl.lua │ │ ├── constants.lua │ │ └── ffi.lua │ ├── nr.lua │ ├── ppc64le │ │ ├── ioctl.lua │ │ └── ffi.lua │ ├── ppc │ │ ├── ioctl.lua │ │ └── ffi.lua │ ├── netfilter.lua │ ├── cgroup.lua │ ├── fcntl.lua │ ├── sockopt.lua │ └── mips │ │ ├── ioctl.lua │ │ └── ffi.lua ├── osx │ ├── sysctl.lua │ ├── util.lua │ ├── fcntl.lua │ ├── c.lua │ ├── syscalls.lua │ ├── errors.lua │ └── ioctl.lua ├── freebsd │ ├── sysctl.lua │ ├── util.lua │ ├── version.lua │ ├── fcntl.lua │ ├── c.lua │ ├── syscalls.lua │ ├── errors.lua │ └── ioctl.lua ├── openbsd │ ├── sysctl.lua │ ├── util.lua │ ├── version.lua │ ├── syscalls.lua │ ├── fcntl.lua │ ├── c.lua │ ├── errors.lua │ └── ioctl.lua ├── netbsd │ ├── version.lua │ ├── fcntl.lua │ ├── init.lua │ ├── c.lua │ ├── errors.lua │ ├── syscalls.lua │ ├── ffifunctions.lua │ └── util.lua ├── rump │ └── ffirump.lua ├── abi.lua ├── ffitypes.lua ├── bit.lua ├── libc.lua ├── lfs.lua └── compat.lua ├── .gitignore ├── docker-compose.test.yml ├── .dockerignore ├── Dockerfile ├── test ├── ctest.lua ├── check-rockspec.sh ├── strict.lua ├── globals.sh ├── openbsd.lua ├── osx.lua ├── helpers.lua ├── rump.lua ├── servetests.lua ├── freebsd.lua ├── ctest-openbsd.lua ├── ctest-osx.lua └── ctest-freebsd.lua ├── .gitmodules ├── doc ├── README.md ├── constants.lua └── COPYRIGHT ├── examples ├── rump │ ├── fstest.lua │ ├── fstest4.lua │ ├── fstest3.lua │ └── fstest2.lua ├── cstub.c ├── kdump ├── sigint.lua ├── vlan.lua ├── init.lua ├── event.lua ├── cbuild.sh ├── epoll.lua └── lxc.lua ├── COPYRIGHT ├── rockspec ├── ljsyscall-0.5-1.rockspec ├── ljsyscall-0.6-1.rockspec ├── ljsyscall-rump-0.9-1.rockspec ├── ljsyscall-rump-0.10-1.rockspec ├── ljsyscall-0.7-1.rockspec └── ljsyscall-0.8-1.rockspec ├── .travis.yml ├── INSTALL ├── syscall.lua └── ChangeLog /syscall/linux/mipsel: -------------------------------------------------------------------------------- 1 | mips -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # misc temp files 2 | tmp/* 3 | *~ 4 | *.core 5 | ktrace.out 6 | obj/* 7 | -------------------------------------------------------------------------------- /docker-compose.test.yml: -------------------------------------------------------------------------------- 1 | sut: 2 | build: . 3 | command: /test/test.lua 4 | volumes: 5 | - ./test:/test 6 | -------------------------------------------------------------------------------- /syscall/linux/x64/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- x64 ioctl differences 2 | 3 | local arch = { 4 | ioctl = { 5 | } 6 | } 7 | 8 | return arch 9 | 10 | -------------------------------------------------------------------------------- /syscall/linux/x86/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- x86 ioctl differences 2 | 3 | local arch = { 4 | ioctl = { 5 | } 6 | } 7 | 8 | return arch 9 | 10 | -------------------------------------------------------------------------------- /syscall/linux/arm64/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- arm64 ioctl differences 2 | 3 | local arch = { 4 | ioctl = { 5 | } 6 | } 7 | 8 | return arch 9 | 10 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.md 3 | COPYRIGHT 4 | ChangeLog 5 | Dockerfile 6 | INSTALL 7 | doc 8 | *.yml 9 | examples 10 | include 11 | rockspec 12 | test 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.4 2 | RUN apk update && apk add luajit luajit-dev strace && mkdir -p /usr/share/lua/5.1 3 | COPY . /usr/share/lua/5.1/ 4 | ENTRYPOINT ["luajit"] 5 | -------------------------------------------------------------------------------- /syscall/linux/arm/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- ARM ioctl differences 2 | 3 | local arch = { 4 | ioctl = { 5 | FIOQSIZE = 0x545E, 6 | } 7 | } 8 | 9 | return arch 10 | 11 | -------------------------------------------------------------------------------- /test/ctest.lua: -------------------------------------------------------------------------------- 1 | local abi = require "syscall.abi" 2 | 3 | -- only use this installation for tests 4 | package.path = "./?.lua;" 5 | 6 | require("test.ctest-" .. abi.os) 7 | 8 | -------------------------------------------------------------------------------- /test/check-rockspec.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | for f in `find syscall -name "*.lua"` 3 | do grep $f rockspec/ljsyscall-scm-1.rockspec >/dev/null || echo $f "not in rockspec" 4 | done 5 | 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "include/buildrump.sh"] 2 | path = include/buildrump.sh 3 | url = https://github.com/rumpkernel/buildrump.sh.git 4 | [submodule "include/ffi-reflect"] 5 | path = include/ffi-reflect 6 | url = https://github.com/corsix/ffi-reflect 7 | [submodule "include/linux-kernel-headers"] 8 | path = include/linux-kernel-headers 9 | url = https://github.com/sabotage-linux/kernel-headers.git 10 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # ljsyscall documentation 2 | 3 | This is under development at present, and the best examples are currently the tests, or ask for help with a github issue. 4 | 5 | Currently just experimenting with how to put documentation together. It needs to be cross platform, and explain the common Posix facilities as well as OS versions, either showing all of them or just for the flatform you are interested in. Thinking of experimenting with annotations, but will probably need more metadata. 6 | 7 | Initial experiment with what we need to document ``open``. 8 | 9 | -------------------------------------------------------------------------------- /examples/rump/fstest.lua: -------------------------------------------------------------------------------- 1 | -- this is a simple port of the fstest.c from buildrump.sh just to show it works 2 | 3 | local S = require "syscall" -- your OS functions 4 | 5 | S.setenv("RUMP_VERBOSE", "1") 6 | 7 | local R = require "syscall.rump.init".init("vfs", "fs.kernfs") 8 | 9 | assert(R.mkdir("/kern", "0755")) 10 | assert(R.mount("kernfs", "/kern")) 11 | 12 | local fd = assert(R.open("/kern/version")) 13 | 14 | local str = assert(fd:read(nil, 1024)) 15 | print("kernel version is " .. str) 16 | assert(fd:close()) 17 | 18 | assert(R.reboot()) 19 | 20 | -------------------------------------------------------------------------------- /syscall/linux/x86/constants.lua: -------------------------------------------------------------------------------- 1 | -- x86 specific code 2 | 3 | local arch = {} 4 | 5 | -- x86 register names 6 | arch.REG = { 7 | GS = 0, 8 | FS = 1, 9 | ES = 2, 10 | DS = 3, 11 | EDI = 4, 12 | ESI = 5, 13 | EBP = 6, 14 | ESP = 7, 15 | EBX = 8, 16 | EDX = 9, 17 | ECX = 10, 18 | EAX = 11, 19 | TRAPNO = 12, 20 | ERR = 13, 21 | EIP = 14, 22 | CS = 15, 23 | EFL = 16, 24 | UESP = 17, 25 | SS = 18, 26 | } 27 | 28 | return arch 29 | 30 | -------------------------------------------------------------------------------- /syscall/osx/sysctl.lua: -------------------------------------------------------------------------------- 1 | --types for OSX sysctl, incomplete at present 2 | 3 | local require = require 4 | 5 | local c = require "syscall.osx.constants" 6 | 7 | local types = { 8 | kern = {c.CTL.KERN, c.KERN}, 9 | ["kern.ostype"] = "string", 10 | ["kern.osrelease"] = "string", 11 | ["kern.osrev"] = "int", 12 | ["kern.version"] = "string", 13 | ["kern.maxvnodes"] = "int", 14 | ["kern.maxproc"] = "int", 15 | ["kern.maxfiles"] = "int", 16 | ["kern.argmax"] = "int", 17 | ["kern.securelvl"] = "int", 18 | ["kern.hostname"] = "string", 19 | ["kern.hostid"] = "int", 20 | } 21 | 22 | return types 23 | 24 | 25 | -------------------------------------------------------------------------------- /syscall/freebsd/sysctl.lua: -------------------------------------------------------------------------------- 1 | --types for FreeBSD sysctl, incomplete at present 2 | 3 | local require = require 4 | 5 | local c = require "syscall.freebsd.constants" 6 | 7 | local types = { 8 | kern = {c.CTL.KERN, c.KERN}, 9 | ["kern.ostype"] = "string", 10 | ["kern.osrelease"] = "string", 11 | ["kern.osrev"] = "int", 12 | ["kern.version"] = "string", 13 | ["kern.maxvnodes"] = "int", 14 | ["kern.maxproc"] = "int", 15 | ["kern.maxfiles"] = "int", 16 | ["kern.argmax"] = "int", 17 | ["kern.securelvl"] = "int", 18 | ["kern.hostname"] = "string", 19 | ["kern.hostid"] = "int", 20 | } 21 | 22 | return types 23 | 24 | -------------------------------------------------------------------------------- /syscall/openbsd/sysctl.lua: -------------------------------------------------------------------------------- 1 | --types for OpenBSD sysctl, incomplete at present 2 | 3 | local require = require 4 | 5 | local c = require "syscall.openbsd.constants" 6 | 7 | local types = { 8 | kern = {c.CTL.KERN, c.KERN}, 9 | ["kern.ostype"] = "string", 10 | ["kern.osrelease"] = "string", 11 | ["kern.osrev"] = "int", 12 | ["kern.version"] = "string", 13 | ["kern.maxvnodes"] = "int", 14 | ["kern.maxproc"] = "int", 15 | ["kern.maxfiles"] = "int", 16 | ["kern.argmax"] = "int", 17 | ["kern.securelvl"] = "int", 18 | ["kern.hostname"] = "string", 19 | ["kern.hostid"] = "int", 20 | } 21 | 22 | return types 23 | 24 | -------------------------------------------------------------------------------- /syscall/linux/x64/constants.lua: -------------------------------------------------------------------------------- 1 | -- x64 specific constants 2 | 3 | local arch = {} 4 | 5 | arch.REG = { 6 | R8 = 0, 7 | R9 = 1, 8 | R10 = 2, 9 | R11 = 3, 10 | R12 = 4, 11 | R13 = 5, 12 | R14 = 6, 13 | R15 = 7, 14 | RDI = 8, 15 | RSI = 9, 16 | RBP = 10, 17 | RBX = 11, 18 | RDX = 12, 19 | RAX = 13, 20 | RCX = 14, 21 | RSP = 15, 22 | RIP = 16, 23 | EFL = 17, 24 | CSGSFS = 18, 25 | ERR = 19, 26 | TRAPNO = 20, 27 | OLDMASK = 21, 28 | CR2 = 22, 29 | } 30 | 31 | return arch 32 | 33 | 34 | -------------------------------------------------------------------------------- /syscall/osx/util.lua: -------------------------------------------------------------------------------- 1 | -- osx utils 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(S) 11 | 12 | local abi, types, c = S.abi, S.types, S.c 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local h = require "syscall.helpers" 16 | 17 | local ffi = require "ffi" 18 | 19 | local octal = h.octal 20 | 21 | local util = {} 22 | 23 | local mt = {} 24 | 25 | 26 | return util 27 | 28 | end 29 | 30 | return {init = init} 31 | 32 | -------------------------------------------------------------------------------- /syscall/freebsd/util.lua: -------------------------------------------------------------------------------- 1 | -- FreeBSD utils 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(S) 11 | 12 | local abi, types, c = S.abi, S.types, S.c 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local h = require "syscall.helpers" 16 | 17 | local ffi = require "ffi" 18 | 19 | local octal = h.octal 20 | 21 | local util = {} 22 | 23 | local mt = {} 24 | 25 | 26 | return util 27 | 28 | end 29 | 30 | return {init = init} 31 | 32 | -------------------------------------------------------------------------------- /syscall/openbsd/util.lua: -------------------------------------------------------------------------------- 1 | -- OpenBSD utils 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(S) 11 | 12 | local abi, types, c = S.abi, S.types, S.c 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local h = require "syscall.helpers" 16 | 17 | local ffi = require "ffi" 18 | 19 | local octal = h.octal 20 | 21 | local util = {} 22 | 23 | local mt = {} 24 | 25 | 26 | return util 27 | 28 | end 29 | 30 | return {init = init} 31 | 32 | -------------------------------------------------------------------------------- /examples/rump/fstest4.lua: -------------------------------------------------------------------------------- 1 | -- test tmpfs 2 | 3 | local oldassert = assert 4 | local function assert(cond, s) 5 | return oldassert(cond, tostring(s)) -- annoyingly, assert does not call tostring! 6 | end 7 | 8 | local helpers = require "syscall.helpers" 9 | 10 | local R = require "syscall.rump.init".init("vfs", "fs.tmpfs") 11 | 12 | print("init") 13 | 14 | assert(R.mkdir("/tmp", "0700")) 15 | 16 | print("mkdir") 17 | 18 | local data = {ta_version = 1, ta_nodes_max=100, ta_size_max=1048576, ta_root_mode=helpers.octal("0700")} 19 | assert(R.mount{dir="/tmp", type="tmpfs", data=data}) 20 | 21 | print("mount") 22 | 23 | assert(R.chdir("/tmp")) 24 | 25 | print("chdir") 26 | 27 | assert(R.reboot()) 28 | 29 | -------------------------------------------------------------------------------- /examples/cstub.c: -------------------------------------------------------------------------------- 1 | /* simple example to show a C file linked with ljsyscall */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | void lerror(lua_State *L, char *msg) { 11 | fprintf(stderr, "\nFATAL ERROR:\n %s: %s\n\n", msg, lua_tostring(L, -1)); 12 | lua_close(L); 13 | exit(1); 14 | } 15 | 16 | int main(void) { 17 | lua_State *L; 18 | 19 | L = luaL_newstate(); 20 | luaL_openlibs(L); 21 | 22 | if (luaL_loadstring(L, "require \"test.test\"")) 23 | lerror(L, "luaL_loadstring() failed"); 24 | if (lua_pcall(L, 0, 0, 0)) 25 | lerror(L, "lua_pcall() failed"); 26 | 27 | lua_close(L); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/kdump: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | local function assert(cond, err, ...) 4 | if cond == nil then error(tostring(err)) end -- annoyingly, assert does not call tostring! 5 | if type(cond) == "function" then return cond, err, ... end 6 | if cond == true then return ... end 7 | return cond, ... 8 | end 9 | 10 | local kfile = arg[1] or "ktrace.out" 11 | 12 | local S = require "syscall" 13 | local N = require "syscall.netbsd.init" 14 | 15 | local fd = assert(S.open(kfile, "rdonly")) 16 | local buf = S.t.buffer(32768) 17 | local n = assert(fd:read(buf, 32768)) 18 | for _, ktr in N.util.kdump(buf, n) do 19 | if ktr.version ~= 2 then error "currently only v2 supported" end 20 | print(ktr) 21 | end 22 | assert(fd:close()) 23 | 24 | -------------------------------------------------------------------------------- /examples/rump/fstest3.lua: -------------------------------------------------------------------------------- 1 | -- this is a simple port of the fstest.c from buildrump.sh just to show it works 2 | 3 | -- version with no loading of S to check for accidental leakage 4 | 5 | local oldassert = assert 6 | local function assert(cond, s) 7 | return oldassert(cond, tostring(s)) -- annoyingly, assert does not call tostring! 8 | end 9 | 10 | local R = require "syscall.rump.init".init("vfs", "fs.kernfs") 11 | 12 | print("init") 13 | 14 | assert(R.mkdir("/kern", "0700")) 15 | 16 | print("mkdir") 17 | 18 | assert(R.mount("kernfs", "/kern")) 19 | 20 | print("mount") 21 | 22 | local fd = assert(R.open("/kern/version")) 23 | 24 | print("open") 25 | 26 | local str = assert(fd:read(nil, 1024)) 27 | print("kernel version is " .. str) 28 | assert(fd:close()) 29 | 30 | assert(R.reboot()) 31 | 32 | -------------------------------------------------------------------------------- /syscall/freebsd/version.lua: -------------------------------------------------------------------------------- 1 | -- detect freebsd version 2 | 3 | local abi = require "syscall.abi" 4 | 5 | -- if not on FreeBSD just return most recent 6 | if abi.os ~= "freebsd" then return {version = 10} end 7 | 8 | local ffi = require "ffi" 9 | 10 | require "syscall.ffitypes" 11 | 12 | ffi.cdef [[ 13 | int sysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen); 14 | ]] 15 | 16 | local sc = ffi.new("int[2]", 1, 24) -- kern.osreldate 17 | local osrevision = ffi.new("int[1]") 18 | local lenp = ffi.new("unsigned long[1]", ffi.sizeof("int")) 19 | local res = ffi.C.sysctl(sc, 2, osrevision, lenp, nil, 0) 20 | if res == -1 then error("cannot identify FreeBSD version") end 21 | 22 | local version = math.floor(osrevision[0] / 100000) -- major version ie 9, 10 23 | 24 | return {version = version} 25 | 26 | -------------------------------------------------------------------------------- /examples/rump/fstest2.lua: -------------------------------------------------------------------------------- 1 | local oldassert = assert 2 | local function assert(cond, s) 3 | return oldassert(cond, tostring(s)) 4 | end 5 | 6 | local S = require "syscall" -- your OS functions 7 | 8 | assert(S.abi.le, "This test requires little endian machine") 9 | 10 | S.setenv("RUMP_VERBOSE", "1") 11 | 12 | local R = require "syscall.rump.init".init("vfs", "fs.sysvbfs", "dev", "dev.disk") 13 | 14 | local dev = "/de-vice" 15 | 16 | assert(R.rump.etfs_register(dev, "buildrump.sh/tests/sysvbfs_le.img", "blk")) 17 | 18 | local stat = assert(R.stat(dev)) 19 | 20 | assert(R.mkdir("/mnt", "0755")) 21 | assert(R.mount("sysvbfs", "/mnt", "rdonly", dev)) 22 | 23 | local fd = assert(R.open("/mnt/README", "rdonly")) 24 | 25 | local str = assert(fd:read()) 26 | 27 | assert(str == "Is that a small file system in your pocket or aren't you happy to see me?\n") 28 | 29 | assert(fd:close()) 30 | 31 | assert(R.unmount("/mnt")) 32 | 33 | -------------------------------------------------------------------------------- /examples/sigint.lua: -------------------------------------------------------------------------------- 1 | -- example of a complex signal handler, in this case produce a Lua backtrace on sigpipe 2 | 3 | local S = require "syscall" 4 | local t = S.t 5 | local c = S.c 6 | local ffi = require "ffi" 7 | 8 | local ip 9 | if ffi.arch == "x86" then ip = c.REG.EIP 10 | elseif ffi.arch == "x64" then ip = c.REG.RIP 11 | else error "unsupported architecture" end 12 | 13 | local backtrace = function() error("sigpipe") end 14 | 15 | local f = t.sa_sigaction(function(s, info, ucontext) 16 | ucontext.uc_mcontext.gregs[ip] = ffi.cast("intptr_t", ffi.cast("void (*)(void)", backtrace)) -- set instruction pointer to g 17 | end) 18 | assert(S.sigaction("pipe", {sigaction = f})) 19 | 20 | -- example code to get interesting stack trace 21 | function bb(x) 22 | assert(S.kill(S.getpid(), "pipe")) 23 | return x + 1 24 | end 25 | 26 | function aa(x) 27 | local c = 2 * bb(x + 1) 28 | print("not here") 29 | return c 30 | end 31 | 32 | aa(2) 33 | 34 | -------------------------------------------------------------------------------- /syscall/linux/nr.lua: -------------------------------------------------------------------------------- 1 | local require, error, assert, tonumber, tostring, 2 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 3 | pcall, type, table, string = 4 | require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string 7 | 8 | local abi = require "syscall.abi" 9 | 10 | local nr = require("syscall.linux." .. abi.arch .. ".nr") 11 | 12 | if nr.SYS.socketcall then nr.socketcalls = { 13 | SOCKET = 1, 14 | BIND = 2, 15 | CONNECT = 3, 16 | LISTEN = 4, 17 | ACCEPT = 5, 18 | GETSOCKNAME = 6, 19 | GETPEERNAME = 7, 20 | SOCKETPAIR = 8, 21 | SEND = 9, 22 | RECV = 10, 23 | SENDTO = 11, 24 | RECVFROM = 12, 25 | SHUTDOWN = 13, 26 | SETSOCKOPT = 14, 27 | GETSOCKOPT = 15, 28 | SENDMSG = 16, 29 | RECVMSG = 17, 30 | ACCEPT4 = 18, 31 | RECVMMSG = 19, 32 | SENDMMSG = 20, 33 | } 34 | end 35 | 36 | return nr 37 | 38 | -------------------------------------------------------------------------------- /syscall/openbsd/version.lua: -------------------------------------------------------------------------------- 1 | -- detect openbsd version 2 | 3 | local abi = require "syscall.abi" 4 | 5 | -- if not on OpenBSD just return most recent 6 | if abi.os ~= "openbsd" then return {version = 201411} end 7 | 8 | local ffi = require "ffi" 9 | 10 | require "syscall.ffitypes" 11 | 12 | ffi.cdef [[ 13 | int sysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen); 14 | ]] 15 | 16 | -- Note has been tested on 5.4, 5.5, 5.6, 5.7 17 | 18 | -- 201211 = 5.2 19 | -- 201305 = 5.3 20 | -- 201311 = 5.4 21 | -- 201405 = 5.5 22 | -- 201411 = 5.6 23 | -- 201505 = 5.7 24 | 25 | local sc = ffi.new("int[2]", 1, 3) -- kern.osrev 26 | local osrevision = ffi.new("int[1]") 27 | local lenp = ffi.new("unsigned long[1]", ffi.sizeof("int")) 28 | local ok, res = ffi.C.sysctl(sc, 2, osrevision, lenp, nil, 0) 29 | if not ok or res == -1 then error "cannot determinate openbsd version" end 30 | 31 | local version = osrevision[0] 32 | 33 | return {version = version} 34 | 35 | -------------------------------------------------------------------------------- /syscall/linux/ppc64le/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- ppc ioctl differences 2 | 3 | local arch = { 4 | IOC = { 5 | SIZEBITS = 13, 6 | DIRBITS = 3, 7 | NONE = 1, 8 | READ = 2, 9 | WRITE = 4, 10 | }, 11 | ioctl = function(_IO, _IOR, _IOW, _IORW) 12 | return { 13 | FIOCLEX = _IO('f', 1), 14 | FIONCLEX = _IO('f', 2), 15 | FIOQSIZE = _IOR('f', 128, "off"), 16 | FIOASYNC = _IOW('f', 125, "int"), 17 | TCGETS = _IOR('t', 19, "termios"), 18 | TCSETS = _IOW('t', 20, "termios"), 19 | TCSETSW = _IOW('t', 21, "termios"), 20 | TCSETSF = _IOW('t', 22, "termios"), 21 | TCSBRK = _IO('t', 29), 22 | TCXONC = _IO('t', 30), 23 | TCFLSH = _IO('t', 31), 24 | TIOCSWINSZ = _IOW('t', 103, "winsize"), 25 | TIOCGWINSZ = _IOR('t', 104, "winsize"), 26 | TIOCOUTQ = _IOR('t', 115, "int"), 27 | TIOCSPGRP = _IOW('t', 118, "int"), 28 | TIOCGPGRP = _IOR('t', 119, "int"), 29 | FIONBIO = _IOW('f', 126, "int"), 30 | FIONREAD = _IOR('f', 127, "int"), 31 | } 32 | end, 33 | } 34 | 35 | return arch 36 | 37 | -------------------------------------------------------------------------------- /syscall/linux/ppc/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- ppc ioctl differences 2 | 3 | local arch = { 4 | IOC = { 5 | SIZEBITS = 13, 6 | DIRBITS = 3, 7 | NONE = 1, 8 | READ = 2, 9 | WRITE = 4, 10 | }, 11 | ioctl = function(_IO, _IOR, _IOW, _IORW) 12 | return { 13 | FIOCLEX = _IO('f', 1), 14 | FIONCLEX = _IO('f', 2), 15 | FIOQSIZE = _IOR('f', 128, "off"), 16 | FIOASYNC = _IOW('f', 125, "int"), 17 | TCGETS = _IOR('t', 19, "termios"), 18 | TCSETS = _IOW('t', 20, "termios"), 19 | TCSETSW = _IOW('t', 21, "termios"), 20 | TCSETSF = _IOW('t', 22, "termios"), 21 | TCSBRK = _IO('t', 29), 22 | TCXONC = _IO('t', 30), 23 | TCFLSH = _IO('t', 31), 24 | TIOCSWINSZ = _IOW('t', 103, "winsize"), 25 | TIOCGWINSZ = _IOR('t', 104, "winsize"), 26 | TIOCOUTQ = _IOR('t', 115, "int"), 27 | TIOCSPGRP = _IOW('t', 118, "int"), 28 | TIOCGPGRP = _IOR('t', 119, "int"), 29 | FIONBIO = _IOW('f', 126, "int"), 30 | FIONREAD = _IOR('f', 127, "int"), 31 | } 32 | end, 33 | } 34 | 35 | return arch 36 | 37 | -------------------------------------------------------------------------------- /examples/vlan.lua: -------------------------------------------------------------------------------- 1 | -- example of how to create a vlan using ljsyscall 2 | -- not in the tests as it will mess up your interfaces and as far as I know you can only create vlans on physical interfaces 3 | 4 | local nl = require "syscall.nl" 5 | 6 | local interface = "eth0" 7 | local vlan = 40 8 | local name = interface .. "." .. tostring(vlan) 9 | 10 | local i = assert(nl.interfaces()) 11 | 12 | local ii = i[interface] 13 | 14 | if not ii then 15 | print("cannot find underlying interface") 16 | os.exit(1) 17 | end 18 | 19 | -- create 20 | 21 | -- equivalent to 22 | -- ip link add link eth0 name eth0.42 type vlan id 40 23 | 24 | ok, err = nl.create_interface{name = name, link = ii.index, type = "vlan", id = vlan} 25 | 26 | --Equivalent using newlink 27 | --ok, err = nl.newlink(0, "create", 0, 0, "link", ii.index, "ifname", name, "linkinfo", {"kind", "vlan", "data", {"id", vlan}}) 28 | 29 | if not ok then 30 | print(err) 31 | os.exit(1) 32 | end 33 | 34 | i:refresh() 35 | 36 | print(i) 37 | 38 | ok, err = nl.dellink(0, "ifname", name) 39 | 40 | if not ok then 41 | print(err) 42 | os.exit(1) 43 | end 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/strict.lua: -------------------------------------------------------------------------------- 1 | -- strict.lua 2 | -- checks uses of undeclared global variables 3 | -- All global variables must be 'declared' through a regular assignment 4 | -- (even assigning nil will do) in a main chunk before being used 5 | -- anywhere or assigned to inside a function. 6 | -- distributed under the Lua license: http://www.lua.org/license.html 7 | 8 | local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget 9 | 10 | local mt = getmetatable(_G) 11 | if mt == nil then 12 | mt = {} 13 | setmetatable(_G, mt) 14 | end 15 | 16 | mt.__declared = {} 17 | 18 | local function what () 19 | local d = getinfo(3, "S") 20 | return d and d.what or "C" 21 | end 22 | 23 | mt.__newindex = function (t, n, v) 24 | if not mt.__declared[n] then 25 | local w = what() 26 | if w ~= "main" and w ~= "C" then 27 | error("assign to undeclared variable '"..n.."'", 2) 28 | end 29 | mt.__declared[n] = true 30 | end 31 | rawset(t, n, v) 32 | end 33 | 34 | mt.__index = function (t, n) 35 | if not mt.__declared[n] and what() ~= "C" then 36 | error("variable '"..n.."' is not declared", 2) 37 | end 38 | return rawget(t, n) 39 | end 40 | 41 | -------------------------------------------------------------------------------- /syscall/linux/arm/constants.lua: -------------------------------------------------------------------------------- 1 | -- arm specific constants 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | local octal = function (s) return tonumber(s, 8) end 13 | 14 | local arch = {} 15 | 16 | arch.O = { 17 | RDONLY = octal('0000'), 18 | WRONLY = octal('0001'), 19 | RDWR = octal('0002'), 20 | ACCMODE = octal('0003'), 21 | CREAT = octal('0100'), 22 | EXCL = octal('0200'), 23 | NOCTTY = octal('0400'), 24 | TRUNC = octal('01000'), 25 | APPEND = octal('02000'), 26 | NONBLOCK = octal('04000'), 27 | DSYNC = octal('010000'), 28 | ASYNC = octal('020000'), 29 | DIRECTORY = octal('040000'), 30 | NOFOLLOW = octal('0100000'), 31 | DIRECT = octal('0200000'), 32 | LARGEFILE = octal('0400000'), 33 | NOATIME = octal('01000000'), 34 | CLOEXEC = octal('02000000'), 35 | SYNC = octal('04010000'), 36 | } 37 | 38 | return arch 39 | 40 | -------------------------------------------------------------------------------- /syscall/linux/arm64/constants.lua: -------------------------------------------------------------------------------- 1 | -- arm64 specific constants 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | local octal = function (s) return tonumber(s, 8) end 13 | 14 | local arch = {} 15 | 16 | arch.O = { 17 | RDONLY = octal('0000'), 18 | WRONLY = octal('0001'), 19 | RDWR = octal('0002'), 20 | ACCMODE = octal('0003'), 21 | CREAT = octal('0100'), 22 | EXCL = octal('0200'), 23 | NOCTTY = octal('0400'), 24 | TRUNC = octal('01000'), 25 | APPEND = octal('02000'), 26 | NONBLOCK = octal('04000'), 27 | DSYNC = octal('010000'), 28 | ASYNC = octal('020000'), 29 | DIRECTORY = octal('040000'), 30 | NOFOLLOW = octal('0100000'), 31 | DIRECT = octal('0200000'), 32 | LARGEFILE = octal('0400000'), 33 | NOATIME = octal('01000000'), 34 | CLOEXEC = octal('02000000'), 35 | SYNC = octal('04010000'), 36 | } 37 | 38 | return arch 39 | -------------------------------------------------------------------------------- /doc/constants.lua: -------------------------------------------------------------------------------- 1 | -- Documentation of constants 2 | 3 | -- Currently taken from FreeBSD man pages, so need Linux/NetBSD/OSX specific ones added 4 | 5 | local d = {} 6 | 7 | d.O = { 8 | RDONLY = "open for reading only", 9 | WRONLY = "open for writing only", 10 | RDWR = "open for reading and writing", 11 | EXEC = "open for execute only", 12 | NONBLOCK = "do not block on open", 13 | APPEND = "append on each write", 14 | CREAT = "create file if it does not exist", 15 | TRUNC = "truncate size to 0", 16 | EXCL = "error if create and file exists", 17 | SHLOCK = "atomically obtain a shared lock", 18 | EXLOCK = "atomically obtain an exclusive lock", 19 | DIRECT = "eliminate or reduce cache effects", 20 | FSYNC = "synchronous writes", 21 | SYNC = "synchronous writes", 22 | NOFOLLOW = "do not follow symlinks", 23 | NOCTTY = "don't assign controlling terminal", 24 | TTY_INIT = "restore default terminal attributes", 25 | DIRECTORY = "error if file is not a directory", 26 | CLOEXEC = "set FD_CLOEXEC upon open", -- TODO should be hyperlink 27 | } 28 | 29 | return d 30 | 31 | -------------------------------------------------------------------------------- /syscall/openbsd/syscalls.lua: -------------------------------------------------------------------------------- 1 | -- OpenBSD specific syscalls 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | return function(S, hh, c, C, types) 13 | 14 | local ret64, retnum, retfd, retbool, retptr = hh.ret64, hh.retnum, hh.retfd, hh.retbool, hh.retptr 15 | 16 | local ffi = require "ffi" 17 | local errno = ffi.errno 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local istype, mktype, getfd = h.istype, h.mktype, h.getfd 22 | 23 | local t, pt, s = types.t, types.pt, types.s 24 | 25 | function S.reboot(howto) return C.reboot(c.RB[howto]) end 26 | 27 | -- pty functions, using libc ones for now; the libc ones use a database of name to dev mappings 28 | function S.ptsname(fd) 29 | local name = ffi.C.ptsname(getfd(fd)) 30 | if not name then return nil end 31 | return ffi.string(name) 32 | end 33 | 34 | function S.grantpt(fd) return retbool(ffi.C.grantpt(getfd(fd))) end 35 | function S.unlockpt(fd) return retbool(ffi.C.unlockpt(getfd(fd))) end 36 | 37 | return S 38 | 39 | end 40 | 41 | -------------------------------------------------------------------------------- /test/globals.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EXIT=0 4 | 5 | # not comprehensive 6 | find . -name syscall.lua -o -name constants.lua | xargs -n1 luajit 7 | if [ $? != 0 ] 8 | then 9 | echo "Lua error" 10 | EXIT=1 11 | fi 12 | 13 | # test for use of globals variables in ways that are not allowed 14 | 15 | # test for set globals, never allowed 16 | 17 | GSET=`find syscall syscall.lua -name '*.lua' | xargs -n1 luajit -bl | grep GSET` 18 | 19 | if [ ! -z "$GSET" ] 20 | then 21 | echo "Error: global variable set" 22 | find syscall syscall.lua -name '*.lua' | xargs -n1 luajit -bl | egrep "BYTECODE|GSET" 23 | EXIT=1 24 | fi 25 | 26 | # test for get globals, only allowed at top of file for specific cases 27 | # this is not a complete test the local assignment could be missing 28 | # these are the ones we use at present 29 | 30 | OK="require|print|error|assert|tonumber|tostring|setmetatable|pairs|ipairs|unpack|rawget|rawset|pcall|type|table|string|math|select|collectgarbage|_G" 31 | 32 | GGET=`find syscall syscall.lua -name '*.lua' | xargs -n1 luajit -bl | grep GGET | egrep -v "$OK"` 33 | 34 | if [ ! -z "$GGET" ] 35 | then 36 | echo "Error: global variable get" 37 | find syscall syscall.lua -name '*.lua' | xargs -n1 luajit -bl | egrep -v "$OK" | egrep "BYTECODE|GGET" 38 | EXIT=1 39 | fi 40 | 41 | exit $EXIT 42 | 43 | -------------------------------------------------------------------------------- /syscall/freebsd/fcntl.lua: -------------------------------------------------------------------------------- 1 | -- FreeBSD fcntl 2 | -- TODO incomplete, lots missing 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local function init(types) 12 | 13 | local c = require "syscall.freebsd.constants" 14 | 15 | local ffi = require "ffi" 16 | 17 | local t, pt, s = types.t, types.pt, types.s 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local ctobool, booltoc = h.ctobool, h.booltoc 22 | 23 | local fcntl = { -- TODO some functionality missing 24 | commands = { 25 | [c.F.SETFL] = function(arg) return c.O[arg] end, 26 | [c.F.SETFD] = function(arg) return c.FD[arg] end, 27 | [c.F.GETLK] = t.flock, 28 | [c.F.SETLK] = t.flock, 29 | [c.F.SETLKW] = t.flock, 30 | }, 31 | ret = { 32 | [c.F.DUPFD] = function(ret) return t.fd(ret) end, 33 | [c.F.DUPFD_CLOEXEC] = function(ret) return t.fd(ret) end, 34 | [c.F.GETFD] = function(ret) return tonumber(ret) end, 35 | [c.F.GETFL] = function(ret) return tonumber(ret) end, 36 | [c.F.GETOWN] = function(ret) return tonumber(ret) end, 37 | [c.F.GETLK] = function(ret, arg) return arg end, 38 | } 39 | } 40 | 41 | return fcntl 42 | 43 | end 44 | 45 | return {init = init} 46 | 47 | -------------------------------------------------------------------------------- /syscall/openbsd/fcntl.lua: -------------------------------------------------------------------------------- 1 | -- OpenBSD fcntl 2 | -- TODO incomplete, lots missing 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local function init(types) 12 | 13 | local c = require "syscall.openbsd.constants" 14 | 15 | local ffi = require "ffi" 16 | 17 | local t, pt, s = types.t, types.pt, types.s 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local ctobool, booltoc = h.ctobool, h.booltoc 22 | 23 | local fcntl = { -- TODO some functionality missing 24 | commands = { 25 | [c.F.SETFL] = function(arg) return c.O[arg] end, 26 | [c.F.SETFD] = function(arg) return c.FD[arg] end, 27 | [c.F.GETLK] = t.flock, 28 | [c.F.SETLK] = t.flock, 29 | [c.F.SETLKW] = t.flock, 30 | }, 31 | ret = { 32 | [c.F.DUPFD] = function(ret) return t.fd(ret) end, 33 | [c.F.DUPFD_CLOEXEC] = function(ret) return t.fd(ret) end, 34 | [c.F.GETFD] = function(ret) return tonumber(ret) end, 35 | [c.F.GETFL] = function(ret) return tonumber(ret) end, 36 | [c.F.GETOWN] = function(ret) return tonumber(ret) end, 37 | [c.F.GETLK] = function(ret, arg) return arg end, 38 | } 39 | } 40 | 41 | return fcntl 42 | 43 | end 44 | 45 | return {init = init} 46 | 47 | -------------------------------------------------------------------------------- /syscall/linux/netfilter.lua: -------------------------------------------------------------------------------- 1 | -- module for netfilter code 2 | -- will cover iptables, ip6tables, ebtables, arptables eventually 3 | -- even less documentation than for netlink but it does not look too bad... 4 | 5 | local require, error, assert, tonumber, tostring, 6 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 7 | pcall, type, table, string = 8 | require, error, assert, tonumber, tostring, 9 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 10 | pcall, type, table, string 11 | 12 | local nf = {} -- exports 13 | 14 | local ffi = require "ffi" 15 | local bit = require "syscall.bit" 16 | local S = require "syscall" 17 | local helpers = require "syscall.helpers" 18 | local c = S.c 19 | local types = S.types 20 | local t, pt, s = types.t, types.pt, types.s 21 | 22 | function nf.socket(family) 23 | return S.socket(family, "raw", "raw") 24 | end 25 | 26 | local level = { 27 | [c.AF.INET] = c.IPPROTO.IP, 28 | [c.AF.INET6] = c.IPPROTO.IPV6, 29 | } 30 | 31 | function nf.version(family) 32 | family = family or c.AF.INET 33 | local sock, err = nf.socket(family) 34 | if not sock then return nil, err end 35 | local rev = t.xt_get_revision() 36 | local max, err = sock:getsockopt(level[family], c.IPT_SO_GET.REVISION_TARGET, rev, s.xt_get_revision); 37 | local ok, cerr = sock:close() 38 | if not ok then return nil, cerr end 39 | if not max then return nil, err end 40 | return max 41 | end 42 | 43 | return nf 44 | 45 | -------------------------------------------------------------------------------- /syscall/linux/cgroup.lua: -------------------------------------------------------------------------------- 1 | -- Linux cgroup API 2 | -- this is all file system operations packaged up to be easier to use 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local function init(S) 12 | 13 | local h = require "syscall.helpers" 14 | local split = h.split 15 | 16 | local abi, types, c = S.abi, S.types, S.c 17 | local t, pt, s = types.t, types.pt, types.s 18 | 19 | local util = S.util 20 | 21 | local cgroup = {} 22 | 23 | local function mkgroup(name) 24 | -- append default location, should be tmpfs mount 25 | if name:sub(1, 1) ~= "/" then return "/sys/fs/cgroup" .. name else return name end 26 | end 27 | 28 | function cgroup.mount(tab) 29 | tab.source = tab.source or "cgroup" 30 | tab.type = "cgroup" 31 | tab.target = mkgroup(tab.target) 32 | return S.mount(tab) 33 | end 34 | 35 | function cgroup.cgroups(ps) 36 | ps = tostring(ps or "self") 37 | local cgf = util.readfile("/proc/" .. ps .. "/cgroup") 38 | local lines = split("\n", cgf) 39 | local cgroups = {} 40 | for i = 1, #lines - 1 do 41 | local parts = split( ":", lines[i]) 42 | cgroups[parts[1]] = {name = parts[2], path = parts[3]} 43 | end 44 | return cgroups 45 | end 46 | 47 | return cgroup 48 | 49 | end 50 | 51 | return {init = init} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /syscall/netbsd/version.lua: -------------------------------------------------------------------------------- 1 | -- detect netbsd version 2 | 3 | local abi = require "syscall.abi" 4 | 5 | local ffi = require "ffi" 6 | 7 | require "syscall.ffitypes" 8 | 9 | local version, major, minor 10 | 11 | local function inlibc_fn(k) return ffi.C[k] end 12 | 13 | -- NetBSD ABI version 14 | -- TODO if running rump on NetBSD the version detection is a bit flaky if the host and rump differ 15 | -- normally this is ok if you init netbsd first and have compat installed for rump, or do not use both... 16 | ffi.cdef[[ 17 | int sysctl(const int *, unsigned int, void *, size_t *, const void *, size_t); 18 | int __sysctl(const int *, unsigned int, void *, size_t *, const void *, size_t); 19 | int rump_getversion(void); 20 | ]] 21 | local sc = ffi.new("int[2]", 1, 3) -- kern.osrev 22 | local osrevision = ffi.new("int[1]") 23 | local lenp = ffi.new("unsigned long[1]", ffi.sizeof("int")) 24 | local major, minor 25 | local ok, res 26 | if abi.host == "netbsd" then 27 | ok, res = pcall(ffi.C.sysctl, sc, 2, osrevision, lenp, nil, 0) 28 | osrevision = osrevision[0] 29 | end 30 | if not ok or res == -1 then if pcall(inlibc_fn, "rump_getversion") then ok, osrevision = pcall(ffi.C.rump_getversion) end end 31 | if not ok then 32 | version = 7 33 | else 34 | major = math.floor(osrevision / 100000000) 35 | minor = math.floor(osrevision / 1000000) - major * 100 36 | version = major 37 | if minor == 99 then version = version + 1 end 38 | end 39 | return {version = version, major = major, minor = minor} 40 | 41 | -------------------------------------------------------------------------------- /syscall/osx/fcntl.lua: -------------------------------------------------------------------------------- 1 | -- OSX fcntl 2 | -- TODO incomplete, lots missing 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local function init(types) 12 | 13 | local c = require "syscall.osx.constants" 14 | 15 | local ffi = require "ffi" 16 | 17 | local t, pt, s = types.t, types.pt, types.s 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local ctobool, booltoc = h.ctobool, h.booltoc 22 | 23 | local fcntl = { 24 | commands = { 25 | [c.F.SETFL] = function(arg) return c.O[arg] end, 26 | [c.F.SETFD] = function(arg) return c.FD[arg] end, 27 | [c.F.GETLK] = t.flock, 28 | [c.F.SETLK] = t.flock, 29 | [c.F.SETLKW] = t.flock, 30 | [c.F.SETNOSIGPIPE] = function(arg) return booltoc(arg) end, 31 | }, 32 | ret = { 33 | [c.F.DUPFD] = function(ret) return t.fd(ret) end, 34 | [c.F.DUPFD_CLOEXEC] = function(ret) return t.fd(ret) end, 35 | [c.F.GETFD] = function(ret) return tonumber(ret) end, 36 | [c.F.GETFL] = function(ret) return tonumber(ret) end, 37 | [c.F.GETOWN] = function(ret) return tonumber(ret) end, 38 | [c.F.GETLK] = function(ret, arg) return arg end, 39 | [c.F.GETNOSIGPIPE] = function(ret) return ctobool(ret) end, 40 | } 41 | } 42 | 43 | return fcntl 44 | 45 | end 46 | 47 | return {init = init} 48 | 49 | -------------------------------------------------------------------------------- /syscall/freebsd/c.lua: -------------------------------------------------------------------------------- 1 | -- This sets up the table of C functions 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | local ffi = require "ffi" 13 | 14 | require "syscall.freebsd.ffi" 15 | 16 | local voidp = ffi.typeof("void *") 17 | 18 | local function void(x) 19 | return ffi.cast(voidp, x) 20 | end 21 | 22 | -- basically all types passed to syscalls are int or long, so we do not need to use nicely named types, so we can avoid importing t. 23 | local int, long = ffi.typeof("int"), ffi.typeof("long") 24 | local uint, ulong = ffi.typeof("unsigned int"), ffi.typeof("unsigned long") 25 | 26 | local function inlibc_fn(k) return ffi.C[k] end 27 | 28 | local C = setmetatable({}, { 29 | __index = function(C, k) 30 | if pcall(inlibc_fn, k) then 31 | C[k] = ffi.C[k] -- add to table, so no need for this slow path again 32 | return C[k] 33 | else 34 | return nil 35 | end 36 | end 37 | }) 38 | 39 | -- quite a few FreeBSD functions are weak aliases to __sys_ prefixed versions, some seem to resolve but others do not, odd. 40 | C.futimes = C.__sys_futimes 41 | C.lutimes = C.__sys_lutimes 42 | C.utimes = C.__sys_utimes 43 | C.wait4 = C.__sys_wait4 44 | C.sigaction = C.__sys_sigaction 45 | 46 | return C 47 | 48 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | The ABI description files (ffifunctions, ffitypes, constants) do not consist of 2 | copyrightable material and should be considered public domain. 3 | 4 | Files under the include directory include their own copyright information. 5 | 6 | 7 | ljsyscall: System call interface for LuaJIT 8 | 9 | Copyright (C) 2011-2016 Justin Cormack. All rights reserved. 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | 29 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 30 | 31 | -------------------------------------------------------------------------------- /syscall/netbsd/fcntl.lua: -------------------------------------------------------------------------------- 1 | -- NetBSD fcntl 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(types) 11 | 12 | local c = require "syscall.netbsd.constants" 13 | 14 | local ffi = require "ffi" 15 | 16 | local t, pt, s = types.t, types.pt, types.s 17 | 18 | local h = require "syscall.helpers" 19 | 20 | local ctobool, booltoc = h.ctobool, h.booltoc 21 | 22 | local fcntl = { 23 | commands = { 24 | [c.F.SETFL] = function(arg) return c.O[arg] end, 25 | [c.F.SETFD] = function(arg) return c.FD[arg] end, 26 | [c.F.GETLK] = t.flock, 27 | [c.F.SETLK] = t.flock, 28 | [c.F.SETLKW] = t.flock, 29 | [c.F.SETNOSIGPIPE] = function(arg) return booltoc(arg) end, 30 | }, 31 | ret = { 32 | [c.F.DUPFD] = function(ret) return t.fd(ret) end, 33 | [c.F.DUPFD_CLOEXEC] = function(ret) return t.fd(ret) end, 34 | [c.F.GETFD] = function(ret) return tonumber(ret) end, 35 | [c.F.GETFL] = function(ret) return tonumber(ret) end, 36 | [c.F.GETOWN] = function(ret) return tonumber(ret) end, 37 | [c.F.GETLK] = function(ret, arg) return arg end, 38 | [c.F.MAXFD] = function(ret) return tonumber(ret) end, 39 | [c.F.GETNOSIGPIPE] = function(ret) return ctobool(ret) end, 40 | } 41 | } 42 | 43 | return fcntl 44 | 45 | end 46 | 47 | return {init = init} 48 | 49 | -------------------------------------------------------------------------------- /examples/init.lua: -------------------------------------------------------------------------------- 1 | #!/bin/luajit 2 | 3 | -- basic init process 4 | -- note we do not catch all errors as we cannot do much about them 5 | 6 | -- note that stdin, stderr should be attached to /dev/console 7 | 8 | package.path = "/lib/?.lua;?" 9 | 10 | local S = require "syscall" 11 | local nl = require "syscall.nl" 12 | 13 | local function fatal(s) 14 | print(s) 15 | os.exit() 16 | end 17 | 18 | function try(f, ...) 19 | local ok, err = f(...) -- could use pcall 20 | if ok then return ok end 21 | print("init: error at line " .. debug.getinfo(2, "l").currentline .. ": " .. tostring(err)) 22 | end 23 | 24 | if not S then fatal("cannot find syscall library") end 25 | 26 | -- mounts 27 | 28 | try(S.mount, "sysfs", "/sys", "sysfs", "rw,nosuid,nodev,noexec,relatime") 29 | try(S.mount, "proc", "/proc", "proc", "rw,nosuid,nodev,noexec,relatime") 30 | try(S.mount, "devpts", "/dev/pts", "devpts", "rw,nosuid,noexec,relatime") 31 | 32 | -- interfaces 33 | 34 | local i = nl.interfaces() 35 | local lo, eth0 = i.lo, i.eth0 36 | 37 | lo:up() 38 | 39 | eth0:up() 40 | 41 | eth0:address("10.3.0.2/24") 42 | 43 | -- hostname 44 | 45 | S.sethostname("lua") 46 | 47 | -- print something 48 | local i = nl.interfaces() 49 | print(i) 50 | 51 | -- run processes 52 | 53 | 54 | -- reap zombies 55 | 56 | while true do 57 | local w, err = S.waitpid(-1, "all") 58 | if not w and err.ECHILD then break end -- no more children 59 | end 60 | 61 | -- childless 62 | 63 | print("last child exited") 64 | 65 | S.pause() -- for testing, normally exit 66 | 67 | 68 | -------------------------------------------------------------------------------- /rockspec/ljsyscall-0.5-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "ljsyscall" 2 | version = "0.5-1" 3 | source = 4 | { 5 | url = "https://github.com/justincormack/ljsyscall/archive/v0.5.tar.gz"; 6 | dir = "ljsyscall-0.5"; 7 | } 8 | description = 9 | { 10 | summary = "LuaJIT Linux syscall FFI"; 11 | homepage = "http://www.myriabit.com/ljsyscall/"; 12 | license = "MIT"; 13 | } 14 | dependencies = 15 | { 16 | "lua == 5.1"; -- In fact this should be "luajit >= 2.0.0" 17 | } 18 | build = 19 | { 20 | type = "none"; 21 | install = 22 | { 23 | lua = 24 | { 25 | ["syscall"] = "syscall.lua"; 26 | ["syscall.constants"] = "syscall/constants.lua"; 27 | ["syscall.headers"] = "syscall/headers.lua"; 28 | ["syscall.helpers"] = "syscall/helpers.lua"; 29 | ["syscall.ioctl"] = "syscall/ioctl.lua"; 30 | ["syscall.types"] = "syscall/types.lua"; 31 | ["syscall.nl"] = "syscall/nl.lua"; 32 | ["syscall.arm.constants"] = "syscall/arm/constants.lua"; 33 | ["syscall.arm.ioctl"] = "syscall/arm/ioctl.lua"; 34 | ["syscall.mips.constants"] = "syscall/mips/constants.lua"; 35 | ["syscall.ppc.constants"] = "syscall/ppc/constants.lua"; 36 | ["syscall.ppc.headers"] = "syscall/ppc/headers.lua"; 37 | ["syscall.ppc.ioctl"] = "syscall/ppc/ioctl.lua"; 38 | ["syscall.x64.constants"] = "syscall/x64/constants.lua"; 39 | ["syscall.x64.headers"] = "syscall/x64/headers.lua"; 40 | ["syscall.x86.constants"] = "syscall/x86/constants.lua"; 41 | ["syscall.x86.headers"] = "syscall/x86/headers.lua"; 42 | }; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /examples/event.lua: -------------------------------------------------------------------------------- 1 | -- example of event ioctls 2 | 3 | local S = require "syscall" 4 | 5 | local EV = S.c.EV 6 | local MSC = S.c.MSC 7 | local KEY = S.c.KEY 8 | 9 | local kl = {} 10 | for k, v in pairs(KEY) do kl[v] = k end 11 | 12 | local oldassert = assert 13 | local function assert(cond, s) 14 | collectgarbage("collect") -- force gc, to test for bugs 15 | return oldassert(cond, tostring(s)) -- annoyingly, assert does not call tostring! 16 | end 17 | 18 | local function ev(dev) 19 | if not dev then dev = "/dev/input/event0" end 20 | local fd = assert(S.open(dev, "rdonly")) 21 | 22 | local version = assert(S.ioctl(fd, "EVIOCGVERSION")) 23 | 24 | print(string.format("evdev driver version: %d.%d.%d", 25 | bit.rshift(version, 16), 26 | bit.band(bit.rshift(version, 8), 0xff), 27 | bit.band(version, 0xff))) 28 | 29 | local ev = S.t.input_event() 30 | while true do 31 | assert(fd:read(ev)) 32 | 33 | if ev.type == EV.MSC then 34 | if ev.code == MSC.SCAN then 35 | print("MSC_SCAN: ", string.format("0x%x", ev.value)); 36 | else 37 | print("MSC: ", ev.code, ev.value); 38 | end 39 | elseif ev.type == EV.KEY then 40 | if ev.value == 1 then print("down", kl[ev.code], ev.code) 41 | elseif ev.value == 0 then print("up", kl[ev.code], ev.code) 42 | elseif ev.value == 2 then print("repeat", kl[ev.code], ev.code) 43 | end 44 | else 45 | --print("EVENT TYPE: ", ev.type, "CODE:", ev.code, "VALUE: ", string.format("0x%x", ev.value)); 46 | end 47 | end 48 | end 49 | 50 | 51 | 52 | ev(arg[1]) 53 | 54 | -------------------------------------------------------------------------------- /syscall/linux/fcntl.lua: -------------------------------------------------------------------------------- 1 | -- fcntl is one of those bits of the Unix API that is a bit random, so give it its own file 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(types) 11 | 12 | local c = require "syscall.linux.constants" 13 | 14 | local ffi = require "ffi" 15 | 16 | local t, pt, s = types.t, types.pt, types.s 17 | 18 | local fcntl = { 19 | commands = { 20 | [c.F.SETFL] = function(arg) return c.O[arg] end, 21 | [c.F.SETFD] = function(arg) return c.FD[arg] end, 22 | [c.F.GETLK] = t.flock, 23 | [c.F.SETLK] = t.flock, 24 | [c.F.SETLKW] = t.flock, 25 | [c.F.ADD_SEALS] = function(arg) return c.F_SEAL[arg] end, 26 | }, 27 | ret = { 28 | [c.F.DUPFD] = function(ret) return t.fd(ret) end, 29 | [c.F.DUPFD_CLOEXEC] = function(ret) return t.fd(ret) end, 30 | [c.F.GETFD] = function(ret) return tonumber(ret) end, 31 | [c.F.GETFL] = function(ret) return tonumber(ret) end, 32 | [c.F.GETLEASE] = function(ret) return tonumber(ret) end, 33 | [c.F.GETOWN] = function(ret) return tonumber(ret) end, 34 | [c.F.GETSIG] = function(ret) return tonumber(ret) end, 35 | [c.F.GETPIPE_SZ] = function(ret) return tonumber(ret) end, 36 | [c.F.GETLK] = function(ret, arg) return arg end, 37 | [c.F.GET_SEALS] = function(ret) return tonumber(ret) end, 38 | } 39 | } 40 | 41 | return fcntl 42 | 43 | end 44 | 45 | return {init = init} 46 | 47 | -------------------------------------------------------------------------------- /syscall/linux/ppc64le/ffi.lua: -------------------------------------------------------------------------------- 1 | -- ppc specific definitions 2 | 3 | return { 4 | termios = [[ 5 | struct termios { 6 | tcflag_t c_iflag; 7 | tcflag_t c_oflag; 8 | tcflag_t c_cflag; 9 | tcflag_t c_lflag; 10 | cc_t c_cc[19]; 11 | cc_t c_line; 12 | speed_t c_ispeed; 13 | speed_t c_ospeed; 14 | }; 15 | ]], 16 | ucontext = [[ 17 | typedef unsigned long greg_t, gregset_t[48]; 18 | typedef struct { 19 | double fpregs[32]; 20 | double fpscr; 21 | unsigned _pad[2]; 22 | } fpregset_t; 23 | typedef struct { 24 | unsigned vrregs[32][4]; 25 | unsigned vrsave; 26 | unsigned _pad[2]; 27 | unsigned vscr; 28 | } vrregset_t; 29 | typedef struct { 30 | gregset_t gregs; 31 | fpregset_t fpregs; 32 | vrregset_t vrregs __attribute__((__aligned__(16))); 33 | } mcontext_t; 34 | typedef struct ucontext { 35 | unsigned long int uc_flags; 36 | struct ucontext *uc_link; 37 | stack_t uc_stack; 38 | sigset_t uc_sigmask; 39 | mcontext_t uc_mcontext; 40 | } ucontext_t; 41 | ]], 42 | stat = [[ 43 | struct stat { 44 | unsigned long st_dev; 45 | unsigned long st_ino; 46 | unsigned long st_nlink; 47 | unsigned int st_mode; 48 | unsigned int st_uid; 49 | unsigned int st_gid; 50 | unsigned int __pad0; 51 | unsigned long st_rdev; 52 | long st_size; 53 | long st_blksize; 54 | long st_blocks; 55 | unsigned long st_atime; 56 | unsigned long st_atime_nsec; 57 | unsigned long st_mtime; 58 | unsigned long st_mtime_nsec; 59 | unsigned long st_ctime; 60 | unsigned long st_ctime_nsec; 61 | long __unused[3]; 62 | }; 63 | ]], 64 | } 65 | 66 | -------------------------------------------------------------------------------- /syscall/linux/x64/ffi.lua: -------------------------------------------------------------------------------- 1 | -- x64 specific definitions 2 | 3 | return { 4 | epoll = [[ 5 | struct epoll_event { 6 | uint32_t events; 7 | epoll_data_t data; 8 | } __attribute__ ((packed)); 9 | ]], 10 | ucontext = [[ 11 | typedef long long greg_t, gregset_t[23]; 12 | typedef struct _fpstate { 13 | unsigned short cwd, swd, ftw, fop; 14 | unsigned long long rip, rdp; 15 | unsigned mxcsr, mxcr_mask; 16 | struct { 17 | unsigned short significand[4], exponent, padding[3]; 18 | } _st[8]; 19 | struct { 20 | unsigned element[4]; 21 | } _xmm[16]; 22 | unsigned padding[24]; 23 | } *fpregset_t; 24 | typedef struct { 25 | gregset_t gregs; 26 | fpregset_t fpregs; 27 | unsigned long long __reserved1[8]; 28 | } mcontext_t; 29 | typedef struct __ucontext { 30 | unsigned long uc_flags; 31 | struct __ucontext *uc_link; 32 | stack_t uc_stack; 33 | mcontext_t uc_mcontext; 34 | sigset_t uc_sigmask; 35 | unsigned long __fpregs_mem[64]; 36 | } ucontext_t; 37 | ]], 38 | stat = [[ 39 | struct stat { 40 | unsigned long st_dev; 41 | unsigned long st_ino; 42 | unsigned long st_nlink; 43 | unsigned int st_mode; 44 | unsigned int st_uid; 45 | unsigned int st_gid; 46 | unsigned int __pad0; 47 | unsigned long st_rdev; 48 | long st_size; 49 | long st_blksize; 50 | long st_blocks; 51 | unsigned long st_atime; 52 | unsigned long st_atime_nsec; 53 | unsigned long st_mtime; 54 | unsigned long st_mtime_nsec; 55 | unsigned long st_ctime; 56 | unsigned long st_ctime_nsec; 57 | long __unused[3]; 58 | }; 59 | ]], 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /syscall/linux/arm64/ffi.lua: -------------------------------------------------------------------------------- 1 | -- arm64 specific definitions 2 | 3 | return { 4 | ucontext = [[ 5 | typedef unsigned long greg_t; 6 | typedef unsigned long gregset_t[34]; 7 | typedef struct { 8 | long double vregs[32]; 9 | unsigned int fpsr; 10 | unsigned int fpcr; 11 | } fpregset_t; 12 | typedef struct sigcontext 13 | { 14 | unsigned long fault_address; 15 | unsigned long regs[31]; 16 | unsigned long sp, pc, pstate; 17 | long double __reserved[256]; 18 | } mcontext_t; 19 | typedef struct __ucontext { 20 | unsigned long uc_flags; 21 | struct ucontext *uc_link; 22 | stack_t uc_stack; 23 | sigset_t uc_sigmask; 24 | mcontext_t uc_mcontext; 25 | } ucontext_t; 26 | ]], 27 | stat = [[ 28 | struct stat { 29 | unsigned long st_dev; 30 | unsigned long st_ino; 31 | unsigned int st_mode; 32 | unsigned int st_nlink; 33 | unsigned int st_uid; 34 | unsigned int st_gid; 35 | unsigned long st_rdev; 36 | unsigned long __pad1; 37 | long st_size; 38 | int st_blksize; 39 | int __pad2; 40 | long st_blocks; 41 | long st_atime; 42 | unsigned long st_atime_nsec; 43 | long st_mtime; 44 | unsigned long st_mtime_nsec; 45 | long st_ctime; 46 | unsigned long st_ctime_nsec; 47 | unsigned int __unused4; 48 | unsigned int __unused5; 49 | }; 50 | ]], 51 | statfs = [[ 52 | struct statfs64 { 53 | unsigned long f_type, f_bsize; 54 | fsblkcnt_t f_blocks, f_bfree, f_bavail; 55 | fsfilcnt_t f_files, f_ffree; 56 | fsid_t f_fsid; 57 | unsigned long f_namelen, f_frsize, f_flags, f_spare[4]; 58 | }; 59 | ]], 60 | } 61 | 62 | -------------------------------------------------------------------------------- /test/openbsd.lua: -------------------------------------------------------------------------------- 1 | -- OpenBSD specific tests 2 | 3 | local function init(S) 4 | 5 | local helpers = require "test.helpers" 6 | local types = S.types 7 | local c = S.c 8 | local abi = S.abi 9 | 10 | local bit = require "syscall.bit" 11 | local ffi = require "ffi" 12 | 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local assert = helpers.assert 16 | 17 | local function fork_assert(cond, err, ...) -- if we have forked we need to fail in main thread not fork 18 | if not cond then 19 | print(tostring(err)) 20 | print(debug.traceback()) 21 | S.exit("failure") 22 | end 23 | if cond == true then return ... end 24 | return cond, ... 25 | end 26 | 27 | local function assert_equal(...) 28 | collectgarbage("collect") -- force gc, to test for bugs 29 | return assert_equals(...) 30 | end 31 | 32 | local teststring = "this is a test string" 33 | local size = 512 34 | local buf = t.buffer(size) 35 | local tmpfile = "XXXXYYYYZZZ4521" .. S.getpid() 36 | local tmpfile2 = "./666666DDDDDFFFF" .. S.getpid() 37 | local tmpfile3 = "MMMMMTTTTGGG" .. S.getpid() 38 | local longfile = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" .. S.getpid() 39 | local efile = "./tmpexXXYYY" .. S.getpid() .. ".sh" 40 | local largeval = math.pow(2, 33) -- larger than 2^32 for testing 41 | local mqname = "ljsyscallXXYYZZ" .. S.getpid() 42 | 43 | local clean = function() 44 | S.rmdir(tmpfile) 45 | S.unlink(tmpfile) 46 | S.unlink(tmpfile2) 47 | S.unlink(tmpfile3) 48 | S.unlink(longfile) 49 | S.unlink(efile) 50 | end 51 | 52 | local test = {} 53 | 54 | return test 55 | 56 | end 57 | 58 | return {init = init} 59 | 60 | -------------------------------------------------------------------------------- /rockspec/ljsyscall-0.6-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "ljsyscall" 2 | version = "0.6-1" 3 | source = 4 | { 5 | url = "https://github.com/justincormack/ljsyscall/archive/v0.6.tar.gz"; 6 | dir = "ljsyscall-0.6"; 7 | } 8 | description = 9 | { 10 | summary = "LuaJIT Linux syscall FFI"; 11 | homepage = "http://www.myriabit.com/ljsyscall/"; 12 | license = "MIT"; 13 | } 14 | dependencies = 15 | { 16 | "lua == 5.1"; -- In fact this should be "luajit >= 2.0.0" 17 | } 18 | build = 19 | { 20 | type = "none"; 21 | install = 22 | { 23 | lua = 24 | { 25 | ["syscall"] = "syscall.lua"; 26 | ["syscall.constants"] = "syscall/constants.lua"; 27 | ["syscall.headers"] = "syscall/headers.lua"; 28 | ["syscall.helpers"] = "syscall/helpers.lua"; 29 | ["syscall.ioctl"] = "syscall/ioctl.lua"; 30 | ["syscall.types"] = "syscall/types.lua"; 31 | ["syscall.nl"] = "syscall/nl.lua"; 32 | ["syscall.util"] = "syscall/util.lua"; 33 | ["syscall.features"] = "syscall/features.lua"; 34 | ["syscall.arm.constants"] = "syscall/arm/constants.lua"; 35 | ["syscall.arm.ioctl"] = "syscall/arm/ioctl.lua"; 36 | ["syscall.mips.constants"] = "syscall/mips/constants.lua"; 37 | ["syscall.ppc.constants"] = "syscall/ppc/constants.lua"; 38 | ["syscall.ppc.headers"] = "syscall/ppc/headers.lua"; 39 | ["syscall.ppc.ioctl"] = "syscall/ppc/ioctl.lua"; 40 | ["syscall.x64.constants"] = "syscall/x64/constants.lua"; 41 | ["syscall.x64.headers"] = "syscall/x64/headers.lua"; 42 | ["syscall.x86.constants"] = "syscall/x86/constants.lua"; 43 | ["syscall.x86.headers"] = "syscall/x86/headers.lua"; 44 | }; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /rockspec/ljsyscall-rump-0.9-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "ljsyscall-rump" 2 | version = "0.9-1" 3 | source = 4 | { 5 | url = "https://github.com/justincormack/ljsyscall/archive/v0.9.tar.gz"; 6 | dir = "ljsyscall-0.9"; 7 | } 8 | 9 | description = 10 | { 11 | summary = "Rump kernel support for LuaJIT syscall FFI"; 12 | homepage = "http://www.myriabit.com/ljsyscall/"; 13 | license = "MIT"; 14 | } 15 | dependencies = 16 | { 17 | "lua == 5.1"; -- In fact this should be "luajit >= 2.0.0" 18 | "ljsyscall == 0.9"; 19 | } 20 | 21 | local netbsd_modules = 22 | { 23 | modules = 24 | { 25 | ["syscall.netbsd.syscalls"] = "syscall/netbsd/syscalls.lua"; 26 | ["syscall.netbsd.c"] = "syscall/netbsd/c.lua"; 27 | ["syscall.netbsd.constants"] = "syscall/netbsd/constants.lua"; 28 | ["syscall.netbsd.ffitypes"] = "syscall/netbsd/ffitypes.lua"; 29 | ["syscall.netbsd.ffifunctions"] = "syscall/netbsd/ffifunctions.lua"; 30 | ["syscall.netbsd.ioctl"] = "syscall/netbsd/ioctl.lua"; 31 | ["syscall.netbsd.types"] = "syscall/netbsd/types.lua"; 32 | ["syscall.netbsd.fcntl"] = "syscall/netbsd/fcntl.lua"; 33 | ["syscall.netbsd.errors"] = "syscall/netbsd/errors.lua"; 34 | ["syscall.netbsd.util"] = "syscall/netbsd/util.lua"; 35 | ["syscall.netbsd.nr"] = "syscall/netbsd/nr.lua"; 36 | } 37 | } 38 | 39 | build = 40 | { 41 | type = "builtin"; 42 | modules = 43 | { 44 | ["syscall.rump.init"] = "syscall/rump/init.lua"; 45 | ["syscall.rump.c"] = "syscall/rump/c.lua"; 46 | ["syscall.rump.ffirump"] = "syscall/rump/ffirump.lua"; 47 | }; 48 | platforms = { 49 | linux = netbsd_modules; 50 | macosx = netbsd_modules; 51 | freebsd = netbsd_modules; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: required 3 | dist: trusty 4 | 5 | addons: 6 | apt: 7 | packages: 8 | - luajit 9 | - luarocks 10 | - strace 11 | 12 | before_install: 13 | - git submodule update --init --recursive 14 | 15 | env: 16 | - LD_LIBRARY_PATH=./include/buildrump.sh/rump/lib 17 | 18 | script: 19 | - luajit test/test.lua 20 | - mkdir -p ./obj 21 | - luajit test/ctest.lua > ./obj/ctest.c && cc -std=c99 ./obj/ctest.c -o ./obj/ctest && ./obj/ctest 22 | - ./test/globals.sh 23 | - test ! -n "`./test/check-rockspec.sh`" 24 | - cd ./include/buildrump.sh && ./buildrump.sh -qq -j16 -V NOSTATICLIB=1 && cd ../.. 25 | - luajit test/test.lua rump 26 | - luajit test/linux-constants.lua x64 > ./obj/c.c && cc -U__i386__ -DBITS_PER_LONG=64 -I./include/linux-kernel-headers/x86_64/include -o ./obj/c ./obj/c.c && ./obj/c 27 | - luajit test/linux-constants.lua x86 > ./obj/c.c && cc -D__i386__ -DBITS_PER_LONG=32 -I./include/linux-kernel-headers/i386/include -o ./obj/c ./obj/c.c && ./obj/c 28 | - luajit test/linux-constants.lua arm > ./obj/c.c && cc -D__ARM_EABI__ -DBITS_PER_LONG=32 -I./include/linux-kernel-headers/arm/include -o ./obj/c ./obj/c.c && ./obj/c 29 | - luajit test/linux-constants.lua ppc > ./obj/c.c && cc -I./include/linux-kernel-headers/powerpc/include -o ./obj/c ./obj/c.c && ./obj/c 30 | - luajit test/linux-constants.lua mips > ./obj/c.c && cc -D__MIPSEL__ -D_MIPS_SIM=_MIPS_SIM_ABI32 -DCONFIG_32BIT -DBITS_PER_LONG=32 -D_MIPS_SZLONG=32 -D__LITTLE_ENDIAN_BITFIELD -D__LITTLE_ENDIAN -DCONFIG_CPU_LITTLE_ENDIAN -I./include/linux-kernel-headers/mips/include -o ./obj/c ./obj/c.c && ./obj/c 31 | - luajit test/linux-structures.lua x64 > ./obj/c.c && cc -U__i386__ -DBITS_PER_LONG=64 -I./include/linux-kernel-headers/x86_64/include -o ./obj/c ./obj/c.c && ./obj/c 32 | 33 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation instructions 2 | 3 | Make sure you have LuaJIT, at least version 2.0.2, installed. 4 | 5 | You need to put the file syscall.lua and the directory syscall and its contents in the same directory where they will be found by LuaJIT. This can vary by system, but you can find out with `luajit -e 'print(package.path)'` for your system. You do not need all the files, you can delete operating system and architecture files you do not require. 6 | 7 | You can use the stable versions in the luarocks repository, or you can install the head version using ```luarocks install rockspec/ljsyscall-scm-1.rockspec``` or one of the other versions in that directory, which will pull the version from github and install in the right place. 8 | 9 | None of the files in include/ are needed to use the code, just to run the tests. You need to run `git submodule update --init --recursive` to load them before running the tests with `luajit test/test.lua`. 10 | 11 | The optional NetBSD rump kernel support requires building the libraries using the `include/buildrump.sh` submodule, for more information see http://rumpkernel.org/ 12 | 13 | There is some work in progress towards other build patterns such as building into a single binary, see in the examples directory, this will have more documentation later; this is currently used by the Xen runtime for example, or can be used to make static executables. If you want to link into a C program (or something else interfacing to C, such as another scripting language), there are some example scripts. `examples/bytecode.sh` creates an `ar` file with all the bytecode in, and `examples/cbuild.sh` makes a hello world program in C with ljsyscall and luajit linked in. These are only intended as examples to be customised as appropriate, and they link in all files not just the required ones for your architecture. 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /syscall/openbsd/c.lua: -------------------------------------------------------------------------------- 1 | -- This sets up the table of C functions 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | local ffi = require "ffi" 13 | 14 | local voidp = ffi.typeof("void *") 15 | 16 | local function void(x) 17 | return ffi.cast(voidp, x) 18 | end 19 | 20 | -- basically all types passed to syscalls are int or long, so we do not need to use nicely named types, so we can avoid importing t. 21 | local int, long = ffi.typeof("int"), ffi.typeof("long") 22 | local uint, ulong = ffi.typeof("unsigned int"), ffi.typeof("unsigned long") 23 | 24 | local function inlibc_fn(k) return ffi.C[k] end 25 | 26 | -- Syscalls that just return ENOSYS but are in libc. Note these might vary by version in future 27 | local nosys_calls = { 28 | timer_create = true, 29 | timer_gettime = true, 30 | timer_settime = true, 31 | timer_delete = true, 32 | timer_getoverrun = true, 33 | } 34 | 35 | local C = setmetatable({}, { 36 | __index = function(C, k) 37 | if nosys_calls[k] then return nil end 38 | if pcall(inlibc_fn, k) then 39 | C[k] = ffi.C[k] -- add to table, so no need for this slow path again 40 | return C[k] 41 | else 42 | return nil 43 | end 44 | end 45 | }) 46 | 47 | -- quite a few OpenBSD functions are weak aliases to __sys_ prefixed versions, some seem to resolve but others do not, odd. 48 | -- this is true, but not needed on OpenBSD? 49 | --C.futimes = ffi.C.__sys_futimes 50 | --C.lutimes = ffi.C.__sys_lutimes 51 | --C.utimes = ffi.C.__sys_utimes 52 | --C.wait4 = ffi.C.__sys_wait4 53 | --C.sigaction = ffi.C.__sys_sigaction 54 | 55 | return C 56 | 57 | -------------------------------------------------------------------------------- /syscall/linux/x86/ffi.lua: -------------------------------------------------------------------------------- 1 | -- x86 specific definitions 2 | 3 | return { 4 | ucontext = [[ 5 | typedef int greg_t, gregset_t[19]; 6 | typedef struct _fpstate { 7 | unsigned long cw, sw, tag, ipoff, cssel, dataoff, datasel; 8 | struct { 9 | unsigned short significand[4], exponent; 10 | } _st[8]; 11 | unsigned long status; 12 | } *fpregset_t; 13 | typedef struct { 14 | gregset_t gregs; 15 | fpregset_t fpregs; 16 | unsigned long oldmask, cr2; 17 | } mcontext_t; 18 | typedef struct __ucontext { 19 | unsigned long uc_flags; 20 | struct __ucontext *uc_link; 21 | stack_t uc_stack; 22 | mcontext_t uc_mcontext; 23 | sigset_t uc_sigmask; 24 | unsigned long __fpregs_mem[28]; 25 | } ucontext_t; 26 | ]], 27 | stat = [[ 28 | struct stat { 29 | unsigned long long st_dev; 30 | unsigned char __pad0[4]; 31 | unsigned long __st_ino; 32 | unsigned int st_mode; 33 | unsigned int st_nlink; 34 | unsigned long st_uid; 35 | unsigned long st_gid; 36 | unsigned long long st_rdev; 37 | unsigned char __pad3[4]; 38 | long long st_size; 39 | unsigned long st_blksize; 40 | unsigned long long st_blocks; 41 | unsigned long st_atime; 42 | unsigned long st_atime_nsec; 43 | unsigned long st_mtime; 44 | unsigned int st_mtime_nsec; 45 | unsigned long st_ctime; 46 | unsigned long st_ctime_nsec; 47 | unsigned long long st_ino; 48 | }; 49 | ]], 50 | statfs = [[ 51 | typedef long statfs_word; 52 | struct statfs64 { 53 | statfs_word f_type; 54 | statfs_word f_bsize; 55 | uint64_t f_blocks; 56 | uint64_t f_bfree; 57 | uint64_t f_bavail; 58 | uint64_t f_files; 59 | uint64_t f_ffree; 60 | kernel_fsid_t f_fsid; 61 | statfs_word f_namelen; 62 | statfs_word f_frsize; 63 | statfs_word f_flags; 64 | statfs_word f_spare[4]; 65 | } __attribute__((packed,aligned(4))); 66 | ]], 67 | } 68 | 69 | -------------------------------------------------------------------------------- /doc/COPYRIGHT: -------------------------------------------------------------------------------- 1 | This documentation is release under the CC0 license 2 | 3 | http://creativecommons.org/publicdomain/zero/1.0/legalcode 4 | 5 | Portions of the FreeBSD documentation are included, which are licensed as below. 6 | Currently this is the constant definitions. 7 | 8 | Copyright (c) 1980, 1991, 1993 9 | The Regents of the University of California. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions 13 | are met: 14 | 1. Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 2. Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | 4. Neither the name of the University nor the names of its contributors 20 | may be used to endorse or promote products derived from this software 21 | without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | SUCH DAMAGE. 34 | 35 | -------------------------------------------------------------------------------- /syscall/linux/arm/ffi.lua: -------------------------------------------------------------------------------- 1 | -- arm specific definitions 2 | 3 | return { 4 | ucontext = [[ 5 | typedef int greg_t, gregset_t[18]; 6 | typedef struct sigcontext { 7 | unsigned long trap_no, error_code, oldmask; 8 | unsigned long arm_r0, arm_r1, arm_r2, arm_r3; 9 | unsigned long arm_r4, arm_r5, arm_r6, arm_r7; 10 | unsigned long arm_r8, arm_r9, arm_r10, arm_fp; 11 | unsigned long arm_ip, arm_sp, arm_lr, arm_pc; 12 | unsigned long arm_cpsr, fault_address; 13 | } mcontext_t; 14 | typedef struct __ucontext { 15 | unsigned long uc_flags; 16 | struct __ucontext *uc_link; 17 | stack_t uc_stack; 18 | mcontext_t uc_mcontext; 19 | sigset_t uc_sigmask; 20 | unsigned long long uc_regspace[64]; 21 | } ucontext_t; 22 | ]], 23 | stat = [[ 24 | struct stat { 25 | unsigned long long st_dev; 26 | unsigned char __pad0[4]; 27 | unsigned long __st_ino; 28 | unsigned int st_mode; 29 | unsigned int st_nlink; 30 | unsigned long st_uid; 31 | unsigned long st_gid; 32 | unsigned long long st_rdev; 33 | unsigned char __pad3[4]; 34 | long long st_size; 35 | unsigned long st_blksize; 36 | unsigned long long st_blocks; 37 | unsigned long st_atime; 38 | unsigned long st_atime_nsec; 39 | unsigned long st_mtime; 40 | unsigned int st_mtime_nsec; 41 | unsigned long st_ctime; 42 | unsigned long st_ctime_nsec; 43 | unsigned long long st_ino; 44 | }; 45 | ]], 46 | statfs = [[ 47 | typedef uint32_t statfs_word; 48 | struct statfs64 { 49 | statfs_word f_type; 50 | statfs_word f_bsize; 51 | uint64_t f_blocks; 52 | uint64_t f_bfree; 53 | uint64_t f_bavail; 54 | uint64_t f_files; 55 | uint64_t f_ffree; 56 | kernel_fsid_t f_fsid; 57 | statfs_word f_namelen; 58 | statfs_word f_frsize; 59 | statfs_word f_flags; 60 | statfs_word f_spare[4]; 61 | } __attribute__((packed,aligned(4))); 62 | ]], 63 | } 64 | 65 | -------------------------------------------------------------------------------- /syscall/linux/ppc/ffi.lua: -------------------------------------------------------------------------------- 1 | -- ppc specific definitions 2 | 3 | return { 4 | termios = [[ 5 | struct termios { 6 | tcflag_t c_iflag; 7 | tcflag_t c_oflag; 8 | tcflag_t c_cflag; 9 | tcflag_t c_lflag; 10 | cc_t c_cc[19]; 11 | cc_t c_line; 12 | speed_t c_ispeed; 13 | speed_t c_ospeed; 14 | }; 15 | ]], 16 | ucontext = [[ 17 | typedef unsigned long greg_t, gregset_t[48]; 18 | typedef struct { 19 | double fpregs[32]; 20 | double fpscr; 21 | unsigned _pad[2]; 22 | } fpregset_t; 23 | typedef struct { 24 | unsigned vrregs[32][4]; 25 | unsigned vrsave; 26 | unsigned _pad[2]; 27 | unsigned vscr; 28 | } vrregset_t; 29 | typedef struct { 30 | gregset_t gregs; 31 | fpregset_t fpregs; 32 | vrregset_t vrregs __attribute__((__aligned__(16))); 33 | } mcontext_t; 34 | typedef struct ucontext { 35 | unsigned long int uc_flags; 36 | struct ucontext *uc_link; 37 | stack_t uc_stack; 38 | int uc_pad[7]; 39 | union uc_regs_ptr { 40 | struct pt_regs *regs; 41 | mcontext_t *uc_regs; 42 | } uc_mcontext; 43 | sigset_t uc_sigmask; 44 | char uc_reg_space[sizeof(mcontext_t) + 12]; /* last for extensibility */ 45 | } ucontext_t; 46 | ]], 47 | stat = [[ 48 | struct stat { 49 | unsigned long long st_dev; 50 | unsigned long long st_ino; 51 | unsigned int st_mode; 52 | unsigned int st_nlink; 53 | unsigned int st_uid; 54 | unsigned int st_gid; 55 | unsigned long long st_rdev; 56 | unsigned long long __pad1; 57 | long long st_size; 58 | int st_blksize; 59 | int __pad2; 60 | long long st_blocks; 61 | int st_atime; 62 | unsigned int st_atime_nsec; 63 | int st_mtime; 64 | unsigned int st_mtime_nsec; 65 | int st_ctime; 66 | unsigned int st_ctime_nsec; 67 | unsigned int __unused4; 68 | unsigned int __unused5; 69 | }; 70 | ]], 71 | } 72 | 73 | -------------------------------------------------------------------------------- /examples/cbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # bundle up all the Lua files. This will be more files than you can possibly need... 4 | 5 | mkdir -p obj 6 | 7 | cd include/luajit-2.0 && make && cd ../.. 8 | 9 | LIBDIR=include/luajit-2.0/src 10 | INCDIR=include/luajit-2.0/src 11 | JITDIR=include/luajit-2.0/src/jit 12 | 13 | # example of how to build a C executable 14 | 15 | [ ! -f syscall.lua ] && echo "This script is designed to be run from top level directory" && exit 16 | 17 | rm -f ./obj/cbuild 18 | rm -f ./obj/*.{o,a} 19 | 20 | FILES=`find syscall.lua syscall -name '*.lua'` 21 | 22 | for f in $FILES 23 | do 24 | NAME=`echo ${f} | sed 's/\.lua//'` 25 | MODNAME=`echo ${NAME} | sed 's@/@.@g'` 26 | luajit -b -t o -n ${MODNAME} ${f} obj/${MODNAME}.o 27 | done 28 | 29 | FILES=`find $JITDIR -name '*.lua'` 30 | 31 | for f in $FILES 32 | do 33 | NAME=`echo ${f} | sed "s@$JITDIR@@g" | sed 's/\.lua//'` 34 | MODNAME=jit`echo ${NAME} | sed 's@/@.@g'` 35 | luajit -b -t o -n ${MODNAME} ${f} obj/${MODNAME}.o 36 | done 37 | 38 | FILES='test/test.lua test/linux.lua test/netbsd.lua test/rump.lua test/servetests.lua include/ffi-reflect/reflect.lua include/luaunit/luaunit.lua include/strict/strict.lua' 39 | 40 | for f in $FILES 41 | do 42 | NAME=`echo ${f} | sed 's/\.lua//'` 43 | MODNAME=`echo ${NAME} | sed 's@/@.@g'` 44 | luajit -b -t o -n ${MODNAME} ${f} obj/${MODNAME}.o 45 | done 46 | 47 | # small stub to create Lua state and call hello world 48 | cc -c -fPIC -I${INCDIR} examples/cstub.c -o obj/cstub.o 49 | 50 | ar cr obj/libtest.a obj/cstub.o obj/syscall*.o obj/jit*.o obj/test*.o obj/include*.o 51 | 52 | #ld -o obj/cbuild --whole-archive obj/libhello.a --no-whole-archive ${LIBDIR}/libluajit.a -ldl -lm 53 | cc -Wl,-E -o obj/cbuild obj/cstub.o ${LIBDIR}/libluajit.a obj/syscall*.o -ldl -lm 54 | 55 | # for OSv - note this requires luajit .o files be built with -fPIC TODO patch and rebuild 56 | cc -shared -fPIC -Wl,-E -o obj/cbuild.so obj/cstub.o ${LIBDIR}/libluajit.a obj/syscall*.o 57 | 58 | #./obj/cbuild 59 | 60 | -------------------------------------------------------------------------------- /test/osx.lua: -------------------------------------------------------------------------------- 1 | -- OSX specific tests 2 | 3 | local function init(S) 4 | 5 | local helpers = require "test.helpers" 6 | local types = S.types 7 | local c = S.c 8 | local abi = S.abi 9 | 10 | local bit = require "syscall.bit" 11 | local ffi = require "ffi" 12 | 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local assert = helpers.assert 16 | 17 | local function fork_assert(cond, err, ...) -- if we have forked we need to fail in main thread not fork 18 | if not cond then 19 | print(tostring(err)) 20 | print(debug.traceback()) 21 | S.exit("failure") 22 | end 23 | if cond == true then return ... end 24 | return cond, ... 25 | end 26 | 27 | local function assert_equal(...) 28 | collectgarbage("collect") -- force gc, to test for bugs 29 | return assert_equals(...) 30 | end 31 | 32 | local teststring = "this is a test string" 33 | local size = 512 34 | local buf = t.buffer(size) 35 | local tmpfile = "XXXXYYYYZZZ4521" .. S.getpid() 36 | local tmpfile2 = "./666666DDDDDFFFF" .. S.getpid() 37 | local tmpfile3 = "MMMMMTTTTGGG" .. S.getpid() 38 | local longfile = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" .. S.getpid() 39 | local efile = "./tmpexXXYYY" .. S.getpid() .. ".sh" 40 | local largeval = math.pow(2, 33) -- larger than 2^32 for testing 41 | local mqname = "ljsyscallXXYYZZ" .. S.getpid() 42 | 43 | local clean = function() 44 | S.rmdir(tmpfile) 45 | S.unlink(tmpfile) 46 | S.unlink(tmpfile2) 47 | S.unlink(tmpfile3) 48 | S.unlink(longfile) 49 | S.unlink(efile) 50 | end 51 | 52 | local test = {} 53 | 54 | test.time = { 55 | -- example of how to emulate clock_gettime() https://gist.github.com/jbenet/1087739 56 | test_clock_get_time = function() 57 | local clock = assert(S.host_get_clock_service(S.mach_host_self(), "CALENDAR")) 58 | local mts = assert(S.clock_get_time(clock)) 59 | assert(S.mach_port_deallocate(nil, clock)) -- TODO this should be gc 60 | end 61 | } 62 | 63 | return test 64 | 65 | end 66 | 67 | return {init = init} 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /syscall/rump/ffirump.lua: -------------------------------------------------------------------------------- 1 | -- ffi type and function definitions for rump kernel functions 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local cdef = require "ffi".cdef 11 | 12 | cdef[[ 13 | typedef struct modinfo { 14 | unsigned int mi_version; 15 | int mi_class; 16 | int (*mi_modcmd)(int, void *); 17 | const char *mi_name; 18 | const char *mi_required; 19 | } const modinfo_t; 20 | 21 | int rump_boot_gethowto(void); 22 | void rump_boot_sethowto(int); 23 | void rump_boot_setsigmodel(int); 24 | void rump_schedule(void); 25 | void rump_unschedule(void); 26 | void rump_printevcnts(void); 27 | int rump_daemonize_begin(void); 28 | int rump_daemonize_done(int); 29 | int rump_init(void); 30 | int rump_init_server(const char *); 31 | 32 | int rump_pub_getversion(void); 33 | int rump_pub_module_init(const struct modinfo * const *, size_t); 34 | int rump_pub_module_fini(const struct modinfo *); 35 | int rump_pub_kernelfsym_load(void *, uint64_t, char *, uint64_t); 36 | struct uio * rump_pub_uio_setup(void *, size_t, off_t, enum rump_uiorw); 37 | size_t rump_pub_uio_getresid(struct uio *); 38 | off_t rump_pub_uio_getoff(struct uio *); 39 | size_t rump_pub_uio_free(struct uio *); 40 | struct kauth_cred* rump_pub_cred_create(uid_t, gid_t, size_t, gid_t *); 41 | void rump_pub_cred_put(struct kauth_cred *); 42 | int rump_pub_lwproc_rfork(int); 43 | int rump_pub_lwproc_newlwp(pid_t); 44 | void rump_pub_lwproc_switch(struct lwp *); 45 | void rump_pub_lwproc_releaselwp(void); 46 | struct lwp * rump_pub_lwproc_curlwp(void); 47 | void rump_pub_lwproc_sysent_usenative(void); 48 | void rump_pub_allbetsareoff_setid(pid_t, int); 49 | 50 | int rump_pub_etfs_register(const char *, const char *, int rump_etfs_type); 51 | 52 | extern int rump_i_know_what_i_am_doing_with_sysents; 53 | void rump_pub_lwproc_sysent_usenative(void); 54 | ]] 55 | 56 | -------------------------------------------------------------------------------- /syscall/osx/c.lua: -------------------------------------------------------------------------------- 1 | -- This sets up the table of C functions 2 | -- For OSX we hope we do not need many overrides 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local abi = require "syscall.abi" 12 | 13 | local ffi = require "ffi" 14 | 15 | local voidp = ffi.typeof("void *") 16 | 17 | local function void(x) 18 | return ffi.cast(voidp, x) 19 | end 20 | 21 | -- basically all types passed to syscalls are int or long, so we do not need to use nicely named types, so we can avoid importing t. 22 | local int, long = ffi.typeof("int"), ffi.typeof("long") 23 | local uint, ulong = ffi.typeof("unsigned int"), ffi.typeof("unsigned long") 24 | 25 | local function inlibc_fn(k) return ffi.C[k] end 26 | 27 | -- Syscalls that just return ENOSYS but are in libc. Note these might vary by version in future 28 | local nosys_calls = { 29 | mlockall = true, 30 | } 31 | 32 | local C = setmetatable({}, { 33 | __index = function(C, k) 34 | if nosys_calls[k] then return nil end 35 | if pcall(inlibc_fn, k) then 36 | C[k] = ffi.C[k] -- add to table, so no need for this slow path again 37 | return C[k] 38 | else 39 | return nil 40 | end 41 | end 42 | }) 43 | 44 | -- new stat structure, else get legacy one; could use syscalls instead 45 | -- does not work for fstatat 46 | C.stat = C.stat64 47 | C.fstat = C.fstat64 48 | C.lstat = C.lstat64 49 | 50 | -- TODO create syscall table. Except I cannot find how to call them, neither C.syscall nor C._syscall seems to exist 51 | --[[ 52 | local getdirentries = 196 53 | local getdirentries64 = 344 54 | 55 | function C.getdirentries(fd, buf, len, basep) 56 | return C._syscall(getdirentries64, int(fd), void(buf), int(len), void(basep)) 57 | end 58 | ]] 59 | 60 | -- cannot find these anywhere! Apparently not there since 64 bit inodes? 61 | --C.getdirentries = ffi.C._getdirentries 62 | --C.sigaction = ffi.C._sigaction 63 | 64 | return C 65 | 66 | 67 | -------------------------------------------------------------------------------- /syscall/linux/sockopt.lua: -------------------------------------------------------------------------------- 1 | -- socket options mapping 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | -- TODO add typemap for cmsghdr from syscall/types.lua as very similar 11 | -- like ioctls and so on, socket options are a random interface that needs some help to make it nice to use 12 | -- we need to know the types of the options (in particular those that are not the default int) 13 | -- in fact many ints are really bool, so nicer to know that too. 14 | 15 | -- example 16 | --c.SOL.SOCKET, c.SO.PASSCRED - bool 17 | 18 | -- note that currently we use c.SOL[level], c.SO[optname] as level, optname for setsockopt and nothing for getsockopt 19 | -- but the second one depends on the first like cmsghdr options and first seems more complex. 20 | 21 | -- eg netfilter uses c.IPPROTO.IP or c.IPPROTO.IPV6 as level and eg c.IPT_SO_GET.REVISION_TARGET as level, optname 22 | -- so you need to pass the level of the socket you opened? We can store with fd if you use methods, so get/set sockopt know... that will be easier as we can't know option names otherwise. 23 | -- although you can always use SOL_SOCKET (1 in Linux, ffff BSD), so need to special case. Lucky ICMP (ipproto 1) has no sockets 24 | 25 | -- IP supports both IP_ (and MULTI_) and eg IPT_ groups - BSD more consistent I think in that IPT is at raw IP socket level 26 | -- so will need some fudging. Obviously the numbers dont overlap (IPT is >=64) see note /usr/include/linux/netfilter_ipv4/ip_tables.h 27 | 28 | -- draft 29 | 30 | -- will be more complex than this 31 | 32 | --[[ 33 | local levelmaps = { 34 | [c.SOL.SOCKET] = c.SO, 35 | 36 | 37 | 38 | } 39 | 40 | local types = { 41 | SO = { 42 | -- or could use [c.SO.ACCEPTCON] but not as nice 43 | ACCEPTCONN = "boolean", -- NB read only, potentially useful to add 44 | BINDTODEVICE = "string", 45 | BROADCAST = "boolean", 46 | -- ... 47 | }, 48 | IP = { 49 | ADD_MEMBERSHIP = t.ip_mreqn, -- IP multicast 50 | 51 | }, 52 | 53 | 54 | } 55 | 56 | ]] 57 | 58 | -------------------------------------------------------------------------------- /syscall.lua: -------------------------------------------------------------------------------- 1 | -- this puts everything into one table ready to use 2 | 3 | local require, print, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string, math = 6 | require, print, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string, math 9 | 10 | local abi = require "syscall.abi" 11 | 12 | if abi.rump and abi.types then abi.os = abi.types end -- pretend to be NetBSD for normal rump, Linux for rumplinux 13 | 14 | if abi.os == "netbsd" then 15 | -- TODO merge 16 | require("syscall.netbsd.ffitypes") 17 | if not abi.rump then 18 | require("syscall.netbsd.ffifunctions") 19 | end 20 | else 21 | require("syscall." .. abi.os .. ".ffi") 22 | end 23 | 24 | local c = require("syscall." .. abi.os .. ".constants") 25 | 26 | local ostypes = require("syscall." .. abi.os .. ".types") 27 | local bsdtypes 28 | if (abi.rump and abi.types == "netbsd") or (not abi.rump and abi.bsd) then 29 | bsdtypes = require("syscall.bsd.types") 30 | end 31 | local types = require "syscall.types".init(c, ostypes, bsdtypes) 32 | 33 | local C 34 | if abi.rump then -- TODO merge these with conditionals 35 | C = require("syscall.rump.c") 36 | else 37 | C = require("syscall." .. abi.os .. ".c") 38 | end 39 | 40 | -- cannot put in S, needed for tests, cannot be put in c earlier due to deps TODO remove see #94 41 | c.IOCTL = require("syscall." .. abi.os .. ".ioctl").init(types) 42 | 43 | local S = require "syscall.syscalls".init(C, c, types) 44 | 45 | S.abi, S.types, S.t, S.c = abi, types, types.t, c -- add to main table returned 46 | 47 | -- add compatibility code 48 | S = require "syscall.compat".init(S) 49 | 50 | -- add functions from libc 51 | S = require "syscall.libc".init(S) 52 | 53 | -- add methods 54 | S = require "syscall.methods".init(S) 55 | 56 | -- add utils 57 | S.util = require "syscall.util".init(S) 58 | 59 | if abi.os == "linux" then 60 | S.cgroup = require "syscall.linux.cgroup".init(S) 61 | S.nl = require "syscall.linux.nl".init(S) 62 | -- TODO add the other Linux specific modules here 63 | end 64 | 65 | S._VERSION = "v0.11pre" 66 | S._DESCRIPTION = "ljsyscall: A Unix system call API for LuaJIT" 67 | S._COPYRIGHT = "Copyright (C) 2011-2014 Justin Cormack. MIT licensed." 68 | 69 | return S 70 | 71 | -------------------------------------------------------------------------------- /syscall/linux/mips/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- MIPS ioctl differences 2 | 3 | local arch = { 4 | IOC = { 5 | SIZEBITS = 13, 6 | DIRBITS = 3, 7 | NONE = 1, 8 | READ = 2, 9 | WRITE = 4, 10 | }, 11 | ioctl = function(_IO, _IOR, _IOW, _IORW) 12 | return { 13 | FIONREAD = 0x467f, 14 | TCSBRK = 0x5405, 15 | TCXONC = 0x5406, 16 | TCFLSH = 0x5407, 17 | TCGETS = {number = 0x540d, read = true, type = "termios"}, 18 | TCSETS = 0x540e, 19 | TCSETSW = 0x540f, 20 | TCSETSF = 0x5410, 21 | TIOCPKT = 0x5470, 22 | TIOCNOTTY = 0x5471, 23 | TIOCSTI = 0x5472, 24 | TIOCSCTTY = 0x5480, 25 | TIOCGSOFTCAR = 0x5481, 26 | TIOCSSOFTCAR = 0x5482, 27 | TIOCLINUX = 0x5483, 28 | TIOCGSERIAL = 0x5484, 29 | TIOCSSERIAL = 0x5485, 30 | TCSBRKP = 0x5486, 31 | TIOCSERCONFIG = 0x5488, 32 | TIOCSERGWILD = 0x5489, 33 | TIOCSERSWILD = 0x548a, 34 | TIOCGLCKTRMIOS = 0x548b, 35 | TIOCSLCKTRMIOS = 0x548c, 36 | TIOCSERGSTRUCT = 0x548d, 37 | TIOCSERGETLSR = 0x548e, 38 | TIOCSERGETMULTI= 0x548f, 39 | TIOCSERSETMULTI= 0x5490, 40 | TIOCMIWAIT = 0x5491, 41 | TIOCGICOUNT = 0x5492, 42 | FIOCLEX = 0x6601, 43 | FIONCLEX = 0x6602, 44 | FIOASYNC = 0x667d, 45 | FIONBIO = 0x667e, 46 | FIOQSIZE = 0x667f, 47 | TIOCGETD = 0x7400, 48 | TIOCSETD = 0x7401, 49 | TIOCEXCL = 0x740d, 50 | TIOCNXCL = 0x740e, 51 | TIOCGSID = 0x7416, 52 | TIOCMSET = 0x741a, 53 | TIOCMBIS = 0x741b, 54 | TIOCMBIC = 0x741c, 55 | TIOCMGET = 0x741d, 56 | TIOCOUTQ = 0x7472, 57 | FIOGETOWN = _IOR('f', 123, "int"), 58 | FIOSETOWN = _IOW('f', 124, "int"), 59 | SIOCATMARK = _IOR('s', 7, "int"), 60 | SIOCSPGRP = _IOW('s', 8, "pid"), 61 | SIOCGPGRP = _IOR('s', 9, "pid"), 62 | TIOCSWINSZ = _IOW('t', 103, "winsize"), 63 | TIOCGWINSZ = _IOR('t', 104, "winsize"), 64 | TIOCSPGRP = _IOW('t', 118, "int"), 65 | TIOCGPGRP = _IOR('t', 119, "int"), 66 | TIOCCONS = _IOW('t', 120, "int"), 67 | } 68 | end, 69 | } 70 | 71 | return arch 72 | 73 | -------------------------------------------------------------------------------- /syscall/abi.lua: -------------------------------------------------------------------------------- 1 | -- This simply returns ABI information 2 | -- Makes it easier to substitute for non-ffi solution, eg to run tests 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local ffi = require "ffi" 12 | 13 | local function inlibc_fn(k) return ffi.C[k] end 14 | 15 | local abi = { 16 | arch = ffi.arch, -- ppc, x86, arm, x64, mips 17 | abi32 = ffi.abi("32bit"), -- boolean 18 | abi64 = ffi.abi("64bit"), -- boolean 19 | le = ffi.abi("le"), -- boolean 20 | be = ffi.abi("be"), -- boolean 21 | os = ffi.os:lower(), -- bsd, osx, linux 22 | } 23 | 24 | -- Makes no difference to us I believe 25 | if abi.arch == "ppcspe" then abi.arch = "ppc" end 26 | 27 | if abi.arch == "arm" and not ffi.abi("eabi") then error("only support eabi for arm") end 28 | 29 | if (abi.arch == "mips" or abi.arch == "mipsel") then abi.mipsabi = "o32" end -- only one supported now 30 | 31 | if abi.os == "bsd" or abi.os == "osx" then abi.bsd = true end -- some shared BSD functionality 32 | 33 | -- Xen generally behaves like NetBSD, but our tests need to do rump-like setup; bit of a hack 34 | ffi.cdef[[ 35 | int __ljsyscall_under_xen; 36 | ]] 37 | if pcall(inlibc_fn, "__ljsyscall_under_xen") then abi.xen = true end 38 | 39 | -- BSD detection 40 | -- OpenBSD doesn't have sysctlbyname 41 | -- The good news is every BSD has utsname 42 | -- The bad news is that on FreeBSD it is a legacy version that has 32 byte unless you use __xuname 43 | -- fortunately sysname is first so we can use this value 44 | if not abi.xen and not abi.rump and abi.os == "bsd" then 45 | ffi.cdef [[ 46 | struct _utsname { 47 | char sysname[256]; 48 | char nodename[256]; 49 | char release[256]; 50 | char version[256]; 51 | char machine[256]; 52 | }; 53 | int uname(struct _utsname *); 54 | ]] 55 | local uname = ffi.new("struct _utsname") 56 | ffi.C.uname(uname) 57 | abi.os = ffi.string(uname.sysname):lower() 58 | abi.uname = uname 59 | end 60 | 61 | -- rump params 62 | abi.host = abi.os -- real OS, used for rump at present may change this 63 | abi.types = "netbsd" -- you can set to linux, or monkeypatch (see tests) to use Linux types 64 | 65 | return abi 66 | -------------------------------------------------------------------------------- /syscall/osx/syscalls.lua: -------------------------------------------------------------------------------- 1 | -- OSX specific syscalls 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | return function(S, hh, c, C, types) 13 | 14 | local ret64, retnum, retfd, retbool, retptr = hh.ret64, hh.retnum, hh.retfd, hh.retbool, hh.retptr 15 | 16 | local ffi = require "ffi" 17 | local errno = ffi.errno 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local istype, mktype, getfd = h.istype, h.mktype, h.getfd 22 | 23 | local t, pt, s = types.t, types.pt, types.s 24 | 25 | -- TODO lutimes is implemented using setattrlist(2) in OSX 26 | 27 | function S.grantpt(fd) return S.ioctl(fd, "TIOCPTYGRANT") end 28 | function S.unlockpt(fd) return S.ioctl(fd, "TIOCPTYUNLK") end 29 | function S.ptsname(fd) 30 | local buf = t.buffer(128) 31 | local ok, err = S.ioctl(fd, "TIOCPTYGNAME", buf) 32 | if not ok then return nil, err end 33 | return ffi.string(buf) 34 | end 35 | 36 | function S.mach_absolute_time() return C.mach_absolute_time() end 37 | function S.mach_task_self() return C.mach_task_self_ end 38 | function S.mach_host_self() return C.mach_host_self() end 39 | function S.mach_port_deallocate(task, name) return retbool(C.mach_port_deallocate(task or S.mach_task_self(), name)) end 40 | 41 | function S.host_get_clock_service(host, clock_id, clock_serv) 42 | clock_serv = clock_serv or t.clock_serv1() 43 | local ok, err = C.host_get_clock_service(host or S.mach_host_self(), c.CLOCKTYPE[clock_id or "SYSTEM"], clock_serv) 44 | if not ok then return nil, err end 45 | return clock_serv[0] 46 | end 47 | 48 | -- TODO when mach ports do gc, can add 'clock_serv or S.host_get_clock_service()' 49 | function S.clock_get_time(clock_serv, cur_time) 50 | cur_time = cur_time or t.mach_timespec() 51 | local ok, err = C.clock_get_time(clock_serv, cur_time) 52 | if not ok then return nil, err end 53 | return cur_time 54 | end 55 | 56 | -- cannot find out how to get new stat type from fstatat 57 | function S.fstatat(fd, path, buf, flags) 58 | if not buf then buf = t.stat32() end 59 | local ret, err = C.fstatat(c.AT_FDCWD[fd], path, buf, c.AT[flags]) 60 | if ret == -1 then return nil, t.error(err or errno()) end 61 | return buf 62 | end 63 | 64 | return S 65 | 66 | end 67 | 68 | -------------------------------------------------------------------------------- /syscall/netbsd/init.lua: -------------------------------------------------------------------------------- 1 | -- NetBSD init 2 | 3 | -- This returns NetBSD types and constants (but no syscalls) under any OS. 4 | -- Also returns util, which is a bit of a problem, as some of these will use syscalls 5 | -- Currently used by kdump example to get NetBSD ktrace types 6 | 7 | local require = require 8 | 9 | local abi = require "syscall.abi" 10 | 11 | local oldos, oldbsd = abi.os, abi.bsd 12 | 13 | abi.os = "netbsd" 14 | abi.bsd = true 15 | 16 | -- TODO this should be shared with rump! temporarily here 17 | local unchanged = { 18 | char = true, 19 | int = true, 20 | long = true, 21 | unsigned = true, 22 | ["unsigned char"] = true, 23 | ["unsigned int"] = true, 24 | ["unsigned long"] = true, 25 | int8_t = true, 26 | int16_t = true, 27 | int32_t = true, 28 | int64_t = true, 29 | intptr_t = true, 30 | uint8_t = true, 31 | uint16_t = true, 32 | uint32_t = true, 33 | uint64_t = true, 34 | uintptr_t = true, 35 | -- same in all OSs at present 36 | in_port_t = true, 37 | uid_t = true, 38 | gid_t = true, 39 | pid_t = true, 40 | off_t = true, 41 | size_t = true, 42 | ssize_t = true, 43 | socklen_t = true, 44 | ["struct in_addr"] = true, 45 | ["struct in6_addr"] = true, 46 | ["struct iovec"] = true, 47 | ["struct iphdr"] = true, 48 | ["struct udphdr"] = true, 49 | ["struct ethhdr"] = true, 50 | ["struct winsize"] = true, 51 | ["struct {int count; struct iovec iov[?];}"] = true, 52 | } 53 | 54 | local function rumpfn(tp) 55 | if unchanged[tp] then return tp end 56 | if tp == "void (*)(int, siginfo_t *, void *)" then return "void (*)(int, _netbsd_siginfo_t *, void *)" end 57 | if tp == "struct {dev_t dev;}" then return "struct {_netbsd_dev_t dev;}" end 58 | if string.find(tp, "struct") then 59 | return (string.gsub(tp, "struct (%a)", "struct _netbsd_%1")) 60 | end 61 | return "_netbsd_" .. tp 62 | end 63 | 64 | abi.rumpfn = rumpfn 65 | 66 | abi.types = "netbsd" 67 | 68 | local S = {} 69 | 70 | require "syscall.netbsd.ffitypes" 71 | 72 | local ostypes = require "syscall.netbsd.types" 73 | local c = require "syscall.netbsd.constants" 74 | local bsdtypes = require "syscall.bsd.types" 75 | local types = require "syscall.types".init(c, ostypes, bsdtypes) 76 | 77 | c.IOCTL = require("syscall." .. abi.os .. ".ioctl").init(types) 78 | S.c = c 79 | S.types = types 80 | S.t = types.t 81 | S.abi = abi 82 | S.util = require "syscall.util".init(S) 83 | 84 | abi.os, abi.bsd = oldos, oldbsd 85 | abi.rumpfn = nil 86 | 87 | return S 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /test/helpers.lua: -------------------------------------------------------------------------------- 1 | -- misc helper functions 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string, math = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string, math 9 | 10 | local debug, collectgarbage = require "debug", collectgarbage 11 | 12 | local ffi = require "ffi" 13 | local bit = require "bit" 14 | 15 | local h = {} 16 | 17 | -- generic assert helper, mainly for tests 18 | function h.assert(cond, err, ...) 19 | if not cond then 20 | error(tostring(err or "unspecified error")) -- annoyingly, assert does not call tostring! 21 | end 22 | collectgarbage("collect") -- force gc, to test for bugs 23 | if type(cond) == "function" then return cond, err, ... end 24 | if cond == true then return ... end 25 | return cond, ... 26 | end 27 | 28 | -- endian conversion 29 | if ffi.abi("be") then -- nothing to do 30 | function h.htonl(b) return b end 31 | function h.htons(b) return b end 32 | function h.convle32(b) return bit.bswap(b) end -- used by file system capabilities, always stored as le 33 | else 34 | function h.htonl(b) return bit.bswap(b) end 35 | function h.htons(b) return bit.rshift(bit.bswap(b), 16) end 36 | function h.convle32(b) return b end -- used by file system capabilities, always stored as le 37 | end 38 | h.ntohl = h.htonl -- reverse is the same 39 | h.ntohs = h.htons -- reverse is the same 40 | 41 | function h.octal(s) return tonumber(s, 8) end 42 | local octal = h.octal 43 | 44 | function h.split(delimiter, text) 45 | if delimiter == "" then return {text} end 46 | if #text == 0 then return {} end 47 | local list = {} 48 | local pos = 1 49 | while true do 50 | local first, last = text:find(delimiter, pos) 51 | if first then 52 | list[#list + 1] = text:sub(pos, first - 1) 53 | pos = last + 1 54 | else 55 | list[#list + 1] = text:sub(pos) 56 | break 57 | end 58 | end 59 | return list 60 | end 61 | 62 | function h.trim(s) -- TODO should replace underscore with space 63 | return (s:gsub("^%s*(.-)%s*$", "%1")) 64 | end 65 | 66 | local split, trim = h.split, h.trim 67 | 68 | h.divmod = function(a, b) 69 | return math.floor(a / b), a % b 70 | end 71 | 72 | h.booltoc = setmetatable({ 73 | [0] = 0, 74 | [1] = 1, 75 | [false] = 0, 76 | [true] = 1, 77 | }, {__call = function(tb, arg) return tb[arg or 0] end}) -- allow nil as false 78 | 79 | function h.ctobool(i) return tonumber(i) ~= 0 end 80 | 81 | return h 82 | -------------------------------------------------------------------------------- /syscall/ffitypes.lua: -------------------------------------------------------------------------------- 1 | -- these are types which are currently the same for all ports 2 | -- in a module so rump does not import twice 3 | -- note that even if type is same (like pollfd) if the metatype is different cannot be here due to ffi 4 | 5 | -- TODO not sure we want these long term, merge to individual OS files. 6 | 7 | local require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string = 10 | require, error, assert, tonumber, tostring, 11 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 12 | pcall, type, table, string 13 | 14 | local ffi = require "ffi" 15 | 16 | local abi = require "syscall.abi" 17 | 18 | local defs = {} 19 | 20 | local function append(str) defs[#defs + 1] = str end 21 | 22 | append [[ 23 | // 8 bit 24 | typedef unsigned char cc_t; 25 | 26 | // 16 bit 27 | typedef uint16_t in_port_t; 28 | 29 | // 32 bit 30 | typedef uint32_t uid_t; 31 | typedef uint32_t gid_t; 32 | typedef int32_t pid_t; 33 | 34 | typedef unsigned int socklen_t; 35 | 36 | // 64 bit 37 | typedef int64_t off_t; 38 | 39 | // defined as long even though eg NetBSD defines as int on 32 bit, its the same. 40 | typedef long ssize_t; 41 | typedef unsigned long size_t; 42 | 43 | // sighandler in Linux 44 | typedef void (*sig_t)(int); 45 | 46 | struct iovec { 47 | void *iov_base; 48 | size_t iov_len; 49 | }; 50 | struct winsize { 51 | unsigned short ws_row; 52 | unsigned short ws_col; 53 | unsigned short ws_xpixel; 54 | unsigned short ws_ypixel; 55 | }; 56 | struct in_addr { 57 | uint32_t s_addr; 58 | }; 59 | struct in6_addr { 60 | unsigned char s6_addr[16]; 61 | }; 62 | struct ethhdr { 63 | unsigned char h_dest[6]; 64 | unsigned char h_source[6]; 65 | unsigned short h_proto; /* __be16 */ 66 | } __attribute__((packed)); 67 | struct udphdr { 68 | uint16_t source; 69 | uint16_t dest; 70 | uint16_t len; 71 | uint16_t check; 72 | }; 73 | ]] 74 | 75 | -- endian dependent TODO not really, define in independent way 76 | if abi.le then 77 | append [[ 78 | struct iphdr { 79 | uint8_t ihl:4, 80 | version:4; 81 | uint8_t tos; 82 | uint16_t tot_len; 83 | uint16_t id; 84 | uint16_t frag_off; 85 | uint8_t ttl; 86 | uint8_t protocol; 87 | uint16_t check; 88 | uint32_t saddr; 89 | uint32_t daddr; 90 | }; 91 | ]] 92 | else 93 | append [[ 94 | struct iphdr { 95 | uint8_t version:4, 96 | ihl:4; 97 | uint8_t tos; 98 | uint16_t tot_len; 99 | uint16_t id; 100 | uint16_t frag_off; 101 | uint8_t ttl; 102 | uint8_t protocol; 103 | uint16_t check; 104 | uint32_t saddr; 105 | uint32_t daddr; 106 | }; 107 | ]] 108 | end 109 | 110 | ffi.cdef(table.concat(defs, "")) 111 | 112 | 113 | -------------------------------------------------------------------------------- /test/rump.lua: -------------------------------------------------------------------------------- 1 | -- rump specific tests 2 | -- in particular testing the threading, as that is rather different; you can map them to host threads how you like 3 | 4 | local function init(S) 5 | 6 | local helpers = require "test.helpers" 7 | local types = S.types 8 | local c = S.c 9 | local abi = S.abi 10 | local util = S.util 11 | 12 | local bit = require "syscall.bit" 13 | local ffi = require "ffi" 14 | 15 | local t, pt, s = types.t, types.pt, types.s 16 | 17 | local function assert(cond, err, ...) 18 | collectgarbage("collect") -- force gc, to test for bugs 19 | if cond == nil then error(tostring(err)) end -- annoyingly, assert does not call tostring! 20 | if type(cond) == "function" then return cond, err, ... end 21 | if cond == true then return ... end 22 | return cond, ... 23 | end 24 | 25 | local function assert_equal(...) 26 | collectgarbage("collect") -- force gc, to test for bugs 27 | return assert_equals(...) 28 | end 29 | 30 | local test = {} 31 | 32 | test.rump_threads = { 33 | test_create_thread = function() 34 | local origlwp = assert(S.rump.curlwp()) -- we do not run tests in implicit context, so should not fail 35 | assert(S.rump.newlwp(S.getpid())) 36 | local lwp1 = assert(S.rump.curlwp(), "should get a pointer back") 37 | S.rump.releaselwp() 38 | S.rump.switchlwp(origlwp) 39 | end, 40 | test_switch_threads = function() 41 | local origlwp = assert(S.rump.curlwp()) -- we do not run tests in implicit context, so should not fail 42 | local pid = S.getpid() 43 | assert(S.rump.newlwp(pid)) 44 | local lwp1 = assert(S.rump.curlwp(), "should get a pointer back") 45 | assert(S.rump.newlwp(pid)) 46 | local lwp2 = assert(S.rump.curlwp(), "should get a pointer back") 47 | S.rump.switchlwp(lwp1) 48 | S.rump.switchlwp(lwp2) 49 | S.rump.switchlwp(lwp1) 50 | S.rump.releaselwp() 51 | lwp1 = nil 52 | S.rump.switchlwp(lwp2) 53 | S.rump.releaselwp() 54 | lwp2 = nil 55 | S.rump.switchlwp(origlwp) 56 | end, 57 | test_rfork = function() 58 | local pid1 = S.getpid() 59 | local origlwp = assert(S.rump.curlwp()) -- we do not run tests in implicit context, so should not fail 60 | local fd = assert(S.open("/dev/zero", "rdonly")) 61 | assert(fd:read()) -- readable 62 | assert(S.rump.rfork("CFDG")) -- no shared fds 63 | local pid2 = S.getpid() 64 | assert(pid1 ~= pid2, "should have new pid") 65 | local n, err = fd:read() -- should not be able to read this fd 66 | assert(not n and err, "should not be able to access an fd") 67 | S.rump.releaselwp() -- exit this process 68 | S.rump.switchlwp(origlwp) 69 | assert_equal(pid1, S.getpid()) 70 | assert(fd:read()) -- should be able to read /dev/zero now 71 | end, 72 | } 73 | 74 | return test 75 | 76 | end 77 | 78 | return {init = init} 79 | 80 | -------------------------------------------------------------------------------- /syscall/netbsd/c.lua: -------------------------------------------------------------------------------- 1 | -- This sets up the table of C functions for BSD 2 | -- We need to override functions that are versioned as the old ones selected otherwise 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local abi = require "syscall.abi" 12 | 13 | local version = require "syscall.netbsd.version".version 14 | 15 | local ffi = require "ffi" 16 | 17 | local function inlibc_fn(k) return ffi.C[k] end 18 | 19 | -- Syscalls that just return ENOSYS but are in libc. 20 | local nosys_calls 21 | if version == 6 then nosys_calls = { 22 | openat = true, 23 | faccessat = true, 24 | symlinkat = true, 25 | mkdirat = true, 26 | unlinkat = true, 27 | renameat = true, 28 | fstatat = true, 29 | fchmodat = true, 30 | fchownat = true, 31 | mkfifoat = true, 32 | mknodat = true, 33 | } 34 | end 35 | 36 | local C = setmetatable({}, { 37 | __index = function(C, k) 38 | if nosys_calls and nosys_calls[k] then return nil end 39 | if pcall(inlibc_fn, k) then 40 | C[k] = ffi.C[k] -- add to table, so no need for this slow path again 41 | return C[k] 42 | else 43 | return nil 44 | end 45 | end 46 | }) 47 | 48 | -- for NetBSD we use libc names not syscalls, as assume you will have libc linked or statically linked with all symbols exported. 49 | -- this is so we can use NetBSD libc even where syscalls have been redirected to rump calls. 50 | 51 | -- use new versions 52 | C.mount = C.__mount50 53 | C.stat = C.__stat50 54 | C.fstat = C.__fstat50 55 | C.lstat = C.__lstat50 56 | C.getdents = C.__getdents30 57 | C.socket = C.__socket30 58 | C.select = C.__select50 59 | C.pselect = C.__pselect50 60 | C.fhopen = C.__fhopen40 61 | C.fhstat = C.__fhstat50 62 | C.fhstatvfs1 = C.__fhstatvfs140 63 | C.utimes = C.__utimes50 64 | C.posix_fadvise = C.__posix_fadvise50 65 | C.lutimes = C.__lutimes50 66 | C.futimes = C.__futimes50 67 | C.getfh = C.__getfh30 68 | C.kevent = C.__kevent50 69 | C.mknod = C.__mknod50 70 | C.pollts = C.__pollts50 71 | 72 | C.gettimeofday = C.__gettimeofday50 73 | C.settimeofday = C.__settimeofday50 74 | C.adjtime = C.__adjtime50 75 | C.setitimer = C.__setitimer50 76 | C.getitimer = C.__getitimer50 77 | C.clock_gettime = C.__clock_gettime50 78 | C.clock_settime = C.__clock_settime50 79 | C.clock_getres = C.__clock_getres50 80 | C.nanosleep = C.__nanosleep50 81 | C.timer_settime = C.__timer_settime50 82 | C.timer_gettime = C.__timer_gettime50 83 | 84 | -- use underlying syscall not wrapper 85 | C.getcwd = C.__getcwd 86 | 87 | C.sigaction = C.__libc_sigaction14 -- TODO not working I think need to use tramp_sigaction, see also netbsd pause() 88 | 89 | return C 90 | 91 | -------------------------------------------------------------------------------- /rockspec/ljsyscall-rump-0.10-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "ljsyscall-rump" 2 | version = "0.10-1" 3 | source = 4 | { 5 | url = "https://github.com/justincormack/ljsyscall/archive/v0.10.tar.gz"; 6 | dir = "ljsyscall-0.10"; 7 | } 8 | 9 | description = 10 | { 11 | summary = "Rump kernel support for LuaJIT syscall FFI"; 12 | homepage = "http://www.myriabit.com/ljsyscall/"; 13 | license = "MIT"; 14 | } 15 | dependencies = 16 | { 17 | "lua == 5.1"; -- In fact this should be "luajit >= 2.0.0" 18 | "ljsyscall == 0.10"; 19 | } 20 | 21 | local netbsd_modules = 22 | { 23 | modules = 24 | { 25 | ["syscall.netbsd.syscalls"] = "syscall/netbsd/syscalls.lua"; 26 | ["syscall.netbsd.c"] = "syscall/netbsd/c.lua"; 27 | ["syscall.netbsd.constants"] = "syscall/netbsd/constants.lua"; 28 | ["syscall.netbsd.ffitypes"] = "syscall/netbsd/ffitypes.lua"; 29 | ["syscall.netbsd.ffifunctions"] = "syscall/netbsd/ffifunctions.lua"; 30 | ["syscall.netbsd.ioctl"] = "syscall/netbsd/ioctl.lua"; 31 | ["syscall.netbsd.types"] = "syscall/netbsd/types.lua"; 32 | ["syscall.netbsd.fcntl"] = "syscall/netbsd/fcntl.lua"; 33 | ["syscall.netbsd.errors"] = "syscall/netbsd/errors.lua"; 34 | ["syscall.netbsd.util"] = "syscall/netbsd/util.lua"; 35 | ["syscall.netbsd.nr"] = "syscall/netbsd/nr.lua"; 36 | ["syscall.netbsd.init"] = "syscall/netbsd/init.lua"; 37 | ["syscall.netbsd.version"] = "syscall/netbsd/version.lua"; 38 | } 39 | } 40 | 41 | local netbsd_modules_linux = 42 | { 43 | modules = 44 | { 45 | ["syscall.netbsd.syscalls"] = "syscall/netbsd/syscalls.lua"; 46 | ["syscall.netbsd.c"] = "syscall/netbsd/c.lua"; 47 | ["syscall.netbsd.constants"] = "syscall/netbsd/constants.lua"; 48 | ["syscall.netbsd.ffitypes"] = "syscall/netbsd/ffitypes.lua"; 49 | ["syscall.netbsd.ffifunctions"] = "syscall/netbsd/ffifunctions.lua"; 50 | ["syscall.netbsd.ioctl"] = "syscall/netbsd/ioctl.lua"; 51 | ["syscall.netbsd.types"] = "syscall/netbsd/types.lua"; 52 | ["syscall.netbsd.fcntl"] = "syscall/netbsd/fcntl.lua"; 53 | ["syscall.netbsd.errors"] = "syscall/netbsd/errors.lua"; 54 | ["syscall.netbsd.util"] = "syscall/netbsd/util.lua"; 55 | ["syscall.netbsd.nr"] = "syscall/netbsd/nr.lua"; 56 | ["syscall.netbsd.init"] = "syscall/netbsd/init.lua"; 57 | ["syscall.netbsd.version"] = "syscall/netbsd/version.lua"; 58 | 59 | ["syscall.bsd.syscalls"] = "syscall/bsd/syscalls.lua"; 60 | ["syscall.bsd.ffi"] = "syscall/bsd/ffi.lua"; 61 | ["syscall.bsd.types"] = "syscall/bsd/types.lua"; 62 | } 63 | } 64 | 65 | build = 66 | { 67 | type = "builtin"; 68 | modules = 69 | { 70 | ["syscall.rump.init"] = "syscall/rump/init.lua"; 71 | ["syscall.rump.c"] = "syscall/rump/c.lua"; 72 | ["syscall.rump.ffirump"] = "syscall/rump/ffirump.lua"; 73 | }; 74 | platforms = { 75 | linux = netbsd_modules_linux; 76 | macosx = netbsd_modules; 77 | freebsd = netbsd_modules; 78 | openbsd = netbsd_modules; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /syscall/freebsd/syscalls.lua: -------------------------------------------------------------------------------- 1 | -- FreeBSD specific syscalls 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local version = require "syscall.freebsd.version".version 11 | 12 | return function(S, hh, c, C, types) 13 | 14 | local ret64, retnum, retfd, retbool, retptr = hh.ret64, hh.retnum, hh.retfd, hh.retbool, hh.retptr 15 | 16 | local ffi = require "ffi" 17 | local errno = ffi.errno 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local istype, mktype, getfd = h.istype, h.mktype, h.getfd 22 | 23 | local t, pt, s = types.t, types.pt, types.s 24 | 25 | function S.reboot(howto) return C.reboot(c.RB[howto]) end 26 | 27 | if C.bindat then 28 | function S.bindat(dirfd, sockfd, addr, addrlen) 29 | local saddr = pt.sockaddr(addr) 30 | return retbool(C.bindat(c.AT_FDCWD[dirfd], getfd(sockfd), saddr, addrlen or #addr)) 31 | end 32 | end 33 | if C.connectat then 34 | function S.connectat(dirfd, sockfd, addr, addrlen) 35 | local saddr = pt.sockaddr(addr) 36 | return retbool(C.connectat(c.AT_FDCWD[dirfd], getfd(sockfd), saddr, addrlen or #addr)) 37 | end 38 | end 39 | 40 | function S.pdfork(flags, fdp) -- changed order as rarely supply fdp 41 | fdp = fdp or t.int1() 42 | local pid, err = C.pdfork(fdp, c.PD[flags]) 43 | if pid == -1 then return nil, t.error(err or errno()) end 44 | if pid == 0 then return 0 end -- the child does not get an fd 45 | return pid, nil, t.fd(fdp[0]) 46 | end 47 | function S.pdgetpid(fd, pidp) 48 | pidp = pidp or t.int1() 49 | local ok, err = C.pdgetpid(getfd(fd), pidp) 50 | if ok == -1 then return nil, t.error(err or errno()) end 51 | return pidp[0] 52 | end 53 | function S.pdkill(fd, sig) return retbool(C.pdkill(getfd(fd), c.SIG[sig])) end 54 | -- pdwait4 not implemented in FreeBSD yet 55 | 56 | if C.cap_enter and version >= 10 then -- do not support on FreeBSD 9, only partial implementation 57 | function S.cap_enter() return retbool(C.cap_enter()) end 58 | end 59 | if C.cap_getmode and version >= 10 then 60 | function S.cap_getmode(modep) 61 | modep = modep or t.uint1() 62 | local ok, err = C.cap_getmode(modep) 63 | if ok == -1 then return nil, t.error(err or errno()) end 64 | return modep[0] 65 | end 66 | function S.cap_sandboxed() 67 | local modep = S.cap_getmode() 68 | if not modep then return false end 69 | return modep ~= 0 70 | end 71 | end 72 | 73 | -- pty functions 74 | local function isptmaster(fd) return fd:ioctl("TIOCPTMASTER") end 75 | S.grantpt = isptmaster 76 | S.unlockpt = isptmaster 77 | 78 | local SPECNAMELEN = 63 79 | 80 | function S.ptsname(fd) 81 | local ok, err = isptmaster(fd) 82 | if not ok then return nil, err end 83 | local buf = t.buffer(SPECNAMELEN) 84 | local fgn = t.fiodgname_arg{buf = buf, len = SPECNAMELEN} 85 | local ok, err = fd:ioctl("FIODGNAME", fgn) 86 | if not ok then return nil, err end 87 | return "/dev/" .. ffi.string(buf) 88 | end 89 | 90 | return S 91 | 92 | end 93 | 94 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 0.12 release 2 | 3 | + Fix seccomp on arm64 4 | + Linux added support for eBPF 5 | + bug fixes 6 | 7 | 0.11 release 8 | 9 | + OSX time functions 10 | + OSX Mach types 11 | + OSX fixes for Yosemite 12 | + arm64 support 13 | + OpenBSD 5.6, 5.7 and 5.8 support 14 | + ppc64le support, by Gustavo Serra Scalet 15 | + mipsel support 16 | + added Dockerfile, now available on Docker Hub 17 | 18 | 0.10 release 19 | 20 | + Additional ioctls 21 | + FreeBSD 9 support 22 | + Linux MIPS now fully supported 23 | + more timer, clock and signal functions for BSDs. 24 | + error message fixes 25 | + FreeBSD, OSX extended attribute support 26 | + Linux PPC fixes 27 | + Luafilesystem compatibility module 28 | + New rockspecs for stable version, thanks to Hisham 29 | + Add remap_file_pages, thanks to Brian Downing 30 | + Add getpagesize 31 | + All syscalls now direct not via libc on Linux 32 | + OpenBSD support (5.4 and 5.5), thanks to tedu 33 | + sysctl support 34 | + timer_* syscall support 35 | + time functions for rump kernel 36 | + fix backtraces on error 37 | + improved tests for OS versions 38 | + add recvmmsg, sendmmsg 39 | 40 | 0.9 release 41 | 42 | + Bug fixes and better tests 43 | + Reworking of how methods are called 44 | + More NetBSD support 45 | + termios interface rework 46 | + improved ioctl that understands type and direction of arguments 47 | + More NetBSD network config 48 | + Rump kernel Linux ABI support 49 | + Full Linux ppc support, endian fixes 50 | + Android fixes 51 | + Xen support 52 | + kqueue, poll and epoll interface improvements 53 | + additional syscalls 54 | + luaffi supported again 55 | + Better kernel headers and fixes against them 56 | + More Linux MIPS support 57 | + Improved APIs with multiple return values 58 | + Initial NetBSD ktrace support 59 | + FreeBSD support 60 | + More OSX support 61 | + Sharing of common BSD code. 62 | 63 | 0.8 release 64 | 65 | + Rump kernel fixes 66 | + NetBSD 64 bit fixes 67 | + Initial arp/neighbour support 68 | + Work towards MIPS support 69 | + Cmsg cleanup, shm_open, iterators for directory iteration and ls 70 | + More OSX and NetBSD support 71 | + Initial cgroups support 72 | + Initial support of NetBSD network config. 73 | 74 | 0.7 release 75 | 76 | + Bug fixes, general cleanups 77 | + Filesystem capabilities, xattr bug fixes, signal handler functions, cpu affinity support, scheduler functions, POSIX message queues, tun/tap support, ioctl additions and improvements 78 | + Initial NetBSD and OSX support 79 | + Initial NetBSD rump kernel support 80 | + Some fixes to allow Android to work. 81 | 82 | 0.6 release 83 | 84 | + Add support for raw sockets, BPF, seccomp mode 2 (syscall filtering), capabilities 85 | + feature tests 86 | + bug fixes 87 | 88 | 0.5 release 89 | 90 | + Add support for ppc 91 | + Some bug fixes for 64 bit file handling on 32 bit architectures 92 | + Better organisation of files 93 | 94 | 0.4 release 95 | 96 | + Works well with LuaJIT 2.0.0 and has had extensive testing. 97 | + Somewhat modular code now, which makes it easier to use and understand. 98 | 99 | 0.3 release 100 | 101 | + The last release to work with luaffi. 102 | 103 | 0.2 release 104 | 105 | + Work in progress release. 106 | 107 | 0.1 release 108 | 109 | + Very early prototype. 110 | 111 | -------------------------------------------------------------------------------- /syscall/bit.lua: -------------------------------------------------------------------------------- 1 | -- abstract different bit libraries in different lua versions 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | -- TODO add 64 bit operations here 11 | 12 | local ffi = require "ffi" 13 | 14 | local abi = require "syscall.abi" 15 | 16 | local ok, bit 17 | 18 | ok, bit = pcall(require, "bit") 19 | 20 | if not ok then 21 | ok, bit = pcall(require, "bit32") 22 | 23 | local int32 = ffi.typeof("int32_t") 24 | 25 | if not ok then error("no suitable bit library found") end 26 | 27 | -- fixups to make compatible with luajit 28 | bit.tobit = function(x) return tonumber(int32(x)) end 29 | bit.bswap = function(x) 30 | return bit.bor(bit.lshift(bit.extract(x, 0, 8), 24), 31 | bit.lshift(bit.extract(x, 8, 8), 16), 32 | bit.lshift(bit.extract(x, 16, 8), 8), 33 | bit.extract(x, 24, 8)) 34 | end 35 | end 36 | 37 | -- 64 to 32 bit conversions via unions TODO use meth not object? tidy up 38 | local mt 39 | if abi.le then 40 | mt = { 41 | __index = { 42 | to32 = function(u) return u.i32[1], u.i32[0] end, 43 | from32 = function(u, a, b) u.i32[1], u.i32[0] = a, b end, 44 | } 45 | } 46 | else 47 | mt = { 48 | __index = { 49 | to32 = function(u) return u.i32[0], u.i32[1] end, 50 | from32 = function(u, a, b) u.i32[0], u.i32[1] = a, b end, 51 | } 52 | } 53 | end 54 | 55 | mt.__new = function(tp, x) 56 | local n = ffi.new(tp) 57 | n.i64 = x or 0 58 | return n 59 | end 60 | 61 | local i6432 = ffi.metatype("union {int64_t i64; int32_t i32[2];}", mt) 62 | local u6432 = ffi.metatype("union {uint64_t i64; uint32_t i32[2];}", mt) 63 | 64 | bit.i6432 = function(x) return i6432(x):to32() end 65 | bit.u6432 = function(x) return u6432(x):to32() end 66 | 67 | -- initial 64 bit ops. TODO for luajit 2.1 these are not needed, as accepts 64 bit cdata 68 | function bit.bor64(a, b, ...) 69 | local aa, bb, cc = i6432(a), i6432(b), i6432() 70 | cc.i32[0], cc.i32[1] = bit.bor(aa.i32[0], bb.i32[0]), bit.bor(aa.i32[1], bb.i32[1]) 71 | if select('#', ...) > 0 then return bit.bor64(cc.i64, ...) end 72 | return cc.i64 73 | end 74 | 75 | function bit.band64(a, b, ...) 76 | local aa, bb, cc = i6432(a), i6432(b), i6432() 77 | cc.i32[0], cc.i32[1] = bit.band(aa.i32[0], bb.i32[0]), bit.band(aa.i32[1], bb.i32[1]) 78 | if select('#', ...) > 0 then return bit.band64(cc.i64, ...) end 79 | return cc.i64 80 | end 81 | 82 | function bit.lshift64(a, n) 83 | if n == 0 then return a end 84 | local aa, bb = i6432(a), i6432(0) 85 | local ah, al = aa:to32() 86 | local bl, bh = 0, 0 87 | if n < 32 then 88 | bh, bl = bit.lshift(ah, n), bit.lshift(al, n) 89 | bh = bit.bor(bh, bit.rshift(al, 32 - n)) 90 | else 91 | bh, bl = bit.lshift(al, n - 32), 0 92 | end 93 | bb:from32(bh, bl) 94 | return bb.i64 95 | end 96 | 97 | function bit.rshift64(a, n) 98 | if n == 0 then return a end 99 | local aa, bb = i6432(a), i6432(0) 100 | local ah, al = aa:to32() 101 | local bl, bh = 0, 0 102 | if n < 32 then 103 | bh, bl = bit.rshift(ah, n), bit.rshift(al, n) 104 | bl = bit.bor(bl, bit.lshift(ah, 32 - n)) 105 | else 106 | bh, bl = 0, bit.rshift(ah, n - 32) 107 | end 108 | bb:from32(bh, bl) 109 | return bb.i64 110 | end 111 | 112 | return bit 113 | -------------------------------------------------------------------------------- /syscall/libc.lua: -------------------------------------------------------------------------------- 1 | -- things that are libc only, not syscalls 2 | -- this file will not be included if not running with libc eg for rump 3 | 4 | local require, error, assert, tonumber, tostring, 5 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 6 | pcall, type, table, string = 7 | require, error, assert, tonumber, tostring, 8 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 9 | pcall, type, table, string 10 | 11 | local function init(S) 12 | 13 | local c = S.c 14 | local types = S.types 15 | local t, s, pt = types.t, types.s, types.pt 16 | 17 | local ffi = require "ffi" 18 | 19 | local h = require "syscall.helpers" 20 | 21 | local zeropointer = pt.void(0) 22 | 23 | local function retbool(ret) 24 | if ret == -1 then return nil, t.error() end 25 | return true 26 | end 27 | 28 | -- if getcwd not defined, fall back to libc implementation (currently osx, freebsd) 29 | -- freebsd implementation fairly complex 30 | if not S.getcwd then 31 | ffi.cdef [[ 32 | char *getcwd(char *buf, size_t size); 33 | ]] 34 | function S.getcwd(buf, size) 35 | size = size or c.PATH_MAX 36 | buf = buf or t.buffer(size) 37 | local ret = ffi.C.getcwd(buf, size) 38 | if ret == zeropointer then return nil, t.error() end 39 | return ffi.string(buf) 40 | end 41 | end 42 | 43 | -- in NetBSD, OSX exit defined in libc, no _exit syscall available 44 | if not S.exit then 45 | function S.exit(status) return retbool(ffi.C.exit(c.EXIT[status or 0])) end 46 | end 47 | 48 | if not S._exit then 49 | S._exit = S.exit -- provide syscall exit if possible 50 | end 51 | 52 | ffi.cdef [[ 53 | int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle); 54 | ]] 55 | 56 | local function inlibc(k) return ffi.C[k] end 57 | 58 | if pcall(inlibc, "exit") and pcall(inlibc, "__cxa_atexit") then 59 | function S.exit(status) return retbool(ffi.C.exit(c.EXIT[status or 0])) end -- use libc exit instead 60 | function S.atexit(f) return retbool(ffi.C.__cxa_atexit(f, nil, nil)) end 61 | end 62 | 63 | --[[ -- need more types defined 64 | int uname(struct utsname *buf); 65 | time_t time(time_t *t); 66 | ]] 67 | 68 | --[[ 69 | int gethostname(char *name, size_t namelen); 70 | int sethostname(const char *name, size_t len); 71 | int getdomainname(char *name, size_t namelen); 72 | int setdomainname(const char *name, size_t len); 73 | --]] 74 | 75 | -- environment 76 | ffi.cdef [[ 77 | // environment 78 | extern char **environ; 79 | 80 | int setenv(const char *name, const char *value, int overwrite); 81 | int unsetenv(const char *name); 82 | int clearenv(void); 83 | char *getenv(const char *name); 84 | ]] 85 | 86 | function S.environ() -- return whole environment as table 87 | local environ = ffi.C.environ 88 | if not environ then return nil end 89 | local r = {} 90 | local i = 0 91 | while environ[i] ~= zeropointer do 92 | local e = ffi.string(environ[i]) 93 | local eq = e:find('=') 94 | if eq then 95 | r[e:sub(1, eq - 1)] = e:sub(eq + 1) 96 | end 97 | i = i + 1 98 | end 99 | return r 100 | end 101 | 102 | function S.getenv(name) 103 | return S.environ()[name] 104 | end 105 | function S.unsetenv(name) return retbool(ffi.C.unsetenv(name)) end 106 | function S.setenv(name, value, overwrite) 107 | overwrite = h.booltoc(overwrite) -- allows nil as false/0 108 | return retbool(ffi.C.setenv(name, value, overwrite)) 109 | end 110 | function S.clearenv() return retbool(ffi.C.clearenv()) end 111 | 112 | S.errno = ffi.errno 113 | 114 | return S 115 | 116 | end 117 | 118 | return {init = init} 119 | 120 | -------------------------------------------------------------------------------- /syscall/lfs.lua: -------------------------------------------------------------------------------- 1 | -- this is intended to be compatible with luafilesystem https://github.com/keplerproject/luafilesystem 2 | 3 | -- currently does not implement locks 4 | 5 | local require, error, assert, tonumber, tostring, 6 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 7 | pcall, type, table, string = 8 | require, error, assert, tonumber, tostring, 9 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 10 | pcall, type, table, string 11 | 12 | -- TODO allow use eg with rump kernel, needs an initialisation option 13 | -- maybe return a table with a metatable that allows init or uses default if no init? 14 | local S = require "syscall" 15 | 16 | -- TODO not implemented 17 | -- lfs.lock_dir 18 | -- lfs.lock 19 | -- unlock 20 | 21 | local function lfswrap(f) 22 | return function(...) 23 | local ret, err = f(...) 24 | if not ret then return nil, tostring(err) end 25 | return ret 26 | end 27 | end 28 | 29 | local lfs = {} 30 | 31 | lfs._VERSION = "ljsyscall lfs 1" 32 | 33 | local attributes = { 34 | dev = "dev", 35 | ino = "ino", 36 | mode = "typename", -- not sure why lfs insists on calling this mode 37 | nlink = "nlink", 38 | uid = "uid", 39 | gid = "gid", 40 | rdev = "rdev", 41 | access = "access", 42 | modification = "modification", 43 | change = "change", 44 | size = "size", 45 | blocks = "blocks", 46 | blksize = "blksize", 47 | } 48 | 49 | local function attr(st, aname) 50 | if aname then 51 | aname = attributes[aname] 52 | return st[aname] 53 | end 54 | local ret = {} 55 | for k, v in pairs(attributes) do ret[k] = st[v] end 56 | return ret 57 | end 58 | 59 | function lfs.attributes(filepath, aname) 60 | local st, err = S.stat(filepath) 61 | if not st then return nil, tostring(err) end 62 | return attr(st, aname) 63 | end 64 | function lfs.symlinkattributes(filepath, aname) 65 | local st, err = S.lstat(filepath) 66 | if not st then return nil, tostring(err) end 67 | return attr(st, aname) 68 | end 69 | 70 | lfs.chdir = lfswrap(S.chdir) 71 | lfs.currentdir = lfswrap(S.getcwd) 72 | lfs.rmdir = lfswrap(S.rmdir) 73 | lfs.touch = lfswrap(S.utime) 74 | 75 | function lfs.mkdir(path) 76 | local ret, err = S.mkdir(path, "0777") 77 | if not ret then return nil, tostring(err) end 78 | return ret 79 | end 80 | 81 | local function dir_close(dir) 82 | dir.fd:close() 83 | dir.fd = nil 84 | end 85 | 86 | local function dir_next(dir) 87 | if not dir.fd then error "dir ended" end 88 | local d 89 | repeat 90 | if not dir.di then 91 | local err 92 | dir.di, err = dir.fd:getdents(dir.buf, dir.size) 93 | if not dir.di then 94 | dir_close(dir) 95 | error(tostring(err)) -- not sure how we are suppose to handle errors 96 | end 97 | dir.first = true 98 | end 99 | d = dir.di() 100 | if not d then 101 | dir.di = nil 102 | if dir.first then 103 | dir_close(dir) 104 | return nil 105 | end 106 | end 107 | dir.first = false 108 | until d 109 | return d.name 110 | end 111 | 112 | function lfs.dir(path) 113 | local size = 4096 114 | local buf = S.t.buffer(size) 115 | local fd, err = S.open(path, "directory, rdonly") 116 | if err then return nil, tostring(err) end 117 | return dir_next, {size = size, buf = buf, fd = fd, next = dir_next, close = dir_close} 118 | end 119 | 120 | local flink, fsymlink = lfswrap(S.link), lfswrap(S.symlink) 121 | 122 | function lfs.link(old, new, symlink) 123 | if symlink then 124 | return fsymlink(old, new) 125 | else 126 | return flink(old, new) 127 | end 128 | end 129 | 130 | function lfs.setmode(file, mode) return true, "binary" end 131 | 132 | return lfs 133 | 134 | -------------------------------------------------------------------------------- /syscall/linux/mips/ffi.lua: -------------------------------------------------------------------------------- 1 | -- MIPS specific definitions 2 | 3 | -- sigset_t size is set from _NSIG here 4 | 5 | return { 6 | nsig = [[ 7 | static const int _NSIG = 128; 8 | ]], 9 | ucontext = [[ 10 | typedef struct sigaltstack { 11 | void *ss_sp; 12 | size_t ss_size; 13 | int ss_flags; 14 | } stack_t; 15 | typedef struct { 16 | unsigned __mc1[2]; 17 | unsigned long long __mc2[65]; 18 | unsigned __mc3[5]; 19 | unsigned long long __mc4[2]; 20 | unsigned __mc5[6]; 21 | } mcontext_t; 22 | typedef struct __ucontext { 23 | unsigned long uc_flags; 24 | struct __ucontext *uc_link; 25 | stack_t uc_stack; 26 | mcontext_t uc_mcontext; 27 | sigset_t uc_sigmask; 28 | unsigned long uc_regspace[128]; 29 | } ucontext_t; 30 | ]], 31 | sigaction = [[ 32 | struct k_sigaction { 33 | unsigned int sa_flags; 34 | void (*sa_handler)(int); 35 | sigset_t sa_mask; 36 | }; 37 | ]], 38 | siginfo = [[ 39 | /* note renamed members of struct to match other architectures */ 40 | typedef struct siginfo { 41 | int si_signo; 42 | int si_code; 43 | int si_errno; 44 | int __pad0[SI_MAX_SIZE / sizeof(int) - SI_PAD_SIZE - 3]; 45 | 46 | union { 47 | int _pad[SI_PAD_SIZE]; 48 | 49 | struct { 50 | pid_t si_pid; 51 | uid_t si_uid; 52 | } kill; 53 | 54 | struct { 55 | timer_t si_tid; 56 | int si_overrun; 57 | char _pad[sizeof(uid_t) - sizeof(int)]; 58 | sigval_t si_sigval; 59 | int _sys_private; 60 | } timer; 61 | 62 | struct { 63 | pid_t si_pid; 64 | uid_t si_uid; 65 | sigval_t si_sigval; 66 | } rt; 67 | 68 | struct { 69 | pid_t si_pid; 70 | uid_t si_uid; 71 | int si_status; 72 | clock_t si_utime; 73 | clock_t si_stime; 74 | } sigchld; 75 | 76 | struct { 77 | pid_t si_pid; 78 | clock_t si_utime; 79 | int si_status; 80 | clock_t si_stime; 81 | } irix_sigchld; 82 | 83 | struct { 84 | void *si_addr; 85 | short si_addr_lsb; 86 | } sigfault; 87 | 88 | struct { 89 | long si_band; 90 | int si_fd; 91 | } sigpoll; 92 | 93 | struct { 94 | void *si_call_addr; 95 | int si_syscall; 96 | unsigned int si_arch; 97 | } sigsys; 98 | } _sifields; 99 | } siginfo_t; 100 | ]], 101 | -- note this is struct stat64 102 | stat = [[ 103 | struct stat { 104 | unsigned long st_dev; 105 | unsigned long __st_pad0[3]; 106 | unsigned long long st_ino; 107 | mode_t st_mode; 108 | nlink_t st_nlink; 109 | uid_t st_uid; 110 | gid_t st_gid; 111 | unsigned long st_rdev; 112 | unsigned long __st_pad1[3]; 113 | long long st_size; 114 | time_t st_atime; 115 | unsigned long st_atime_nsec; 116 | time_t st_mtime; 117 | unsigned long st_mtime_nsec; 118 | time_t st_ctime; 119 | unsigned long st_ctime_nsec; 120 | unsigned long st_blksize; 121 | unsigned long __st_pad2; 122 | long long st_blocks; 123 | long __st_padding4[14]; 124 | }; 125 | ]], 126 | statfs = [[ 127 | struct statfs64 { 128 | uint32_t f_type; 129 | uint32_t f_bsize; 130 | uint32_t f_frsize; 131 | uint32_t __pad; 132 | uint64_t f_blocks; 133 | uint64_t f_bfree; 134 | uint64_t f_files; 135 | uint64_t f_ffree; 136 | uint64_t f_bavail; 137 | kernel_fsid_t f_fsid; 138 | uint32_t f_namelen; 139 | uint32_t f_flags; 140 | uint32_t f_spare[5]; 141 | }; 142 | ]], 143 | nsig = [[ 144 | static const int _NSIG = 128; 145 | ]], 146 | termios = [[ 147 | struct termios { 148 | tcflag_t c_iflag; 149 | tcflag_t c_oflag; 150 | tcflag_t c_cflag; 151 | tcflag_t c_lflag; 152 | cc_t c_line; 153 | cc_t c_cc[23]; 154 | }; 155 | ]], 156 | } 157 | 158 | -------------------------------------------------------------------------------- /examples/epoll.lua: -------------------------------------------------------------------------------- 1 | -- simple epoll-based socket example. Serves up http responses, but is of course not a proper server 2 | -- you can test performance with ab -n 100000 -c 100 http://localhost:8000/ although ab may be the limiting factor 3 | 4 | local S 5 | if arg[1] == "rump" then 6 | S = require "syscall.rump.init".init{"net", "net.net", "net.local", "net.netinet"} 7 | else 8 | S = require "syscall" 9 | end 10 | 11 | local t, c = S.t, S.c 12 | 13 | local function assert(cond, s, ...) 14 | if cond == nil then error(tostring(s)) end -- annoyingly, assert does not call tostring! 15 | return cond, s, ... 16 | end 17 | 18 | local maxevents = 1024 19 | 20 | local poll 21 | 22 | local function nilf() return nil end 23 | 24 | -- this is somewhat working toward a common API but needs a lot more work, but has resulted in some improvements 25 | if S.epoll_create then 26 | poll = { 27 | init = function(this) 28 | return setmetatable({fd = assert(S.epoll_create())}, {__index = this}) 29 | end, 30 | event = t.epoll_event(), 31 | add = function(this, s) 32 | local event = this.event 33 | event.events = c.EPOLL.IN 34 | event.data.fd = s:getfd() 35 | assert(this.fd:epoll_ctl("add", s, event)) 36 | end, 37 | events = t.epoll_events(maxevents), 38 | get = function(this) 39 | local f, a, r = this.fd:epoll_wait(this.events) 40 | if not f then 41 | print("error on fd", a) 42 | return nilf 43 | else 44 | return f, a, r 45 | end 46 | end, 47 | eof = function(ev) return ev.HUP or ev.ERR or ev.RDHUP end, 48 | } 49 | elseif S.kqueue then 50 | poll = { 51 | init = function(this) 52 | return setmetatable({fd = assert(S.kqueue())}, {__index = this}) 53 | end, 54 | event = t.kevents(1), 55 | add = function(this, s) 56 | local event = this.event[1] 57 | event.fd = s 58 | event.setfilter = "read" 59 | event.setflags = "add" 60 | assert(this.fd:kevent(this.event, nil, 0)) 61 | end, 62 | events = t.kevents(maxevents), 63 | get = function(this) 64 | local f, a, r = this.fd:kevent(nil, this.events) 65 | if not f then 66 | print("error on fd", a) 67 | return nilf 68 | else 69 | return f, a, r 70 | end 71 | end, 72 | eof = function(ev) return ev.EOF or ev.ERROR end, 73 | } 74 | else 75 | error("no epoll or kqueue support") 76 | end 77 | 78 | local s = assert(S.socket("inet", "stream, nonblock")) 79 | 80 | s:setsockopt("socket", "reuseaddr", true) 81 | 82 | local sa = assert(t.sockaddr_in(8000, "127.0.0.1")) 83 | 84 | assert(s:bind(sa)) 85 | 86 | assert(s:listen(128)) 87 | 88 | local ep = poll:init() 89 | 90 | ep:add(s) 91 | 92 | local w = {} 93 | 94 | local msg = [[ 95 | 96 | 97 | performance test 98 | 99 | 100 | test 101 | 102 | 103 | ]] 104 | 105 | local reply = table.concat({ 106 | "HTTP/1.0 200 OK", 107 | "Content-type: text/html", 108 | "Connection: close", 109 | "Content-Length: " .. #msg, 110 | "", 111 | "", 112 | }, "\r\n") .. msg 113 | 114 | 115 | local bufsize = 4096 116 | local buffer = t.buffer(bufsize) 117 | 118 | local ss = t.sockaddr_storage() 119 | 120 | local function loop() 121 | 122 | for i, ev in ep:get() do 123 | 124 | if ep.eof(ev) then 125 | ev.fd:close() 126 | w[ev.fd] = nil 127 | end 128 | 129 | if ev.fd == s:getfd() then -- server socket, accept 130 | repeat 131 | local a, err = s:accept(ss, nil, "nonblock") 132 | if a then 133 | ep:add(a) 134 | w[a:getfd()] = a 135 | end 136 | until not a 137 | else 138 | local fd = w[ev.fd] 139 | fd:read(buffer, bufsize) 140 | local n = fd:write(reply) 141 | assert(n == #reply) 142 | assert(fd:close()) 143 | w[ev.fd] = nil 144 | end 145 | end 146 | 147 | return loop() 148 | 149 | end 150 | 151 | loop() 152 | 153 | 154 | -------------------------------------------------------------------------------- /test/servetests.lua: -------------------------------------------------------------------------------- 1 | -- serve test results, in case operating in an environemnt with no console 2 | 3 | local S = require "syscall" 4 | 5 | -- exit will cause issues, override 6 | os.exit = function() end 7 | 8 | -- open output file 9 | local outname = "output" 10 | local fd = S.creat(outname, "rwxu") 11 | 12 | -- set stdio to file, keep handle so not garbage collected 13 | local stdin = S.dup2(fd, 0) 14 | local stdout = S.dup2(fd, 1) 15 | local stderr = S.dup2(fd, 2) 16 | 17 | -- run tests 18 | require "test.test" 19 | 20 | local st = fd:stat() 21 | 22 | -- close file 23 | fd:close() 24 | 25 | local results = S.util.readfile(outname, nil, st.size) 26 | 27 | -- serve file - this code is borrowed from examples/epoll.lua 28 | local t, c = S.t, S.c 29 | 30 | local function assert(cond, s, ...) 31 | if cond == nil then error(tostring(s)) end -- annoyingly, assert does not call tostring! 32 | return cond, s, ... 33 | end 34 | 35 | local maxevents = 1024 36 | 37 | local poll 38 | 39 | -- this is somewhat working toward a common API but needs a lot more work, but has resulted in some improvements 40 | if S.epoll_create then 41 | poll = { 42 | init = function(this) 43 | return setmetatable({fd = assert(S.epoll_create())}, {__index = this}) 44 | end, 45 | event = t.epoll_event(), 46 | add = function(this, s) 47 | local event = this.event 48 | event.events = c.EPOLL.IN 49 | event.data.fd = s:getfd() 50 | assert(this.fd:epoll_ctl("add", s, event)) 51 | end, 52 | events = t.epoll_events(maxevents), 53 | get = function(this) 54 | return this.fd:epoll_wait(this.events) 55 | end, 56 | eof = function(ev) return ev.HUP or ev.ERR or ev.RDHUP end, 57 | } 58 | elseif S.kqueue then 59 | poll = { 60 | init = function(this) 61 | return setmetatable({fd = assert(S.kqueue())}, {__index = this}) 62 | end, 63 | event = t.kevents(1), 64 | add = function(this, s) 65 | local event = this.event[1] 66 | event.fd = s 67 | event.setfilter = "read" 68 | event.setflags = "add" 69 | assert(this.fd:kevent(this.event, nil, 0)) 70 | end, 71 | events = t.kevents(maxevents), 72 | get = function(this) 73 | return this.fd:kevent(nil, this.events) 74 | end, 75 | eof = function(ev) return ev.EOF or ev.ERROR end, 76 | } 77 | else 78 | error("no epoll or kqueue support") 79 | end 80 | 81 | local s = assert(S.socket("inet", "stream, nonblock")) 82 | 83 | s:setsockopt("socket", "reuseaddr", true) 84 | 85 | local sa = assert(t.sockaddr_in(80, "0.0.0.0")) 86 | 87 | assert(s:bind(sa)) 88 | 89 | assert(s:listen(128)) 90 | 91 | ep = poll:init() 92 | 93 | ep:add(s) 94 | 95 | local w = {} 96 | 97 | local msg = [[ 98 | 99 | 100 | performance test 101 | 102 | 103 | ]] .. results .. [[ 104 | 105 | 106 | ]] 107 | 108 | local reply = table.concat({ 109 | "HTTP/1.0 200 OK", 110 | "Content-type: text/html", 111 | "Connection: close", 112 | "Content-Length: " .. #msg, 113 | "", 114 | "", 115 | }, "\r\n") .. msg 116 | 117 | 118 | local bufsize = 4096 119 | local buffer = t.buffer(bufsize) 120 | 121 | local ss = t.sockaddr_storage() 122 | local addrlen = t.socklen1(#ss) 123 | 124 | local function loop() 125 | 126 | for i, ev in ep:get() do 127 | 128 | if ep.eof(ev) then 129 | fd:close() 130 | w[ev.fileno] = nil 131 | end 132 | 133 | if ev.fd == s.filenum then -- server socket, accept 134 | repeat 135 | local a, err = s:accept("nonblock", ss, addrlen) 136 | if a then 137 | ep:add(a.fd) 138 | w[a.fd:getfd()] = a.fd 139 | end 140 | until not a 141 | else 142 | local fd = w[ev.fd] 143 | fd:read(buffer, bufsize) 144 | local n = fd:write(reply) 145 | assert(n == #reply) 146 | assert(fd:close()) 147 | w[ev.fd] = nil 148 | end 149 | end 150 | 151 | return loop() 152 | 153 | end 154 | 155 | loop() 156 | 157 | -------------------------------------------------------------------------------- /syscall/openbsd/errors.lua: -------------------------------------------------------------------------------- 1 | -- OpenBSD error messages 2 | 3 | local require = require 4 | 5 | local abi = require "syscall.abi" 6 | 7 | local errors = { 8 | PERM = "Operation not permitted", 9 | NOENT = "No such file or directory", 10 | SRCH = "No such process", 11 | INTR = "Interrupted system call", 12 | IO = "Input/output error", 13 | NXIO = "Device not configured", 14 | ["2BIG"] = "Argument list too long", 15 | NOEXEC = "Exec format error", 16 | BADF = "Bad file descriptor", 17 | CHILD = "No child processes", 18 | DEADLK = "Resource deadlock avoided", 19 | NOMEM = "Cannot allocate memory", 20 | ACCES = "Permission denied", 21 | FAULT = "Bad address", 22 | NOTBLK = "Block device required", 23 | BUSY = "Resource busy", 24 | EXIST = "File exists", 25 | XDEV = "Cross-device link", 26 | NODEV = "Operation not supported by device", 27 | NOTDIR = "Not a directory", 28 | ISDIR = "Is a directory", 29 | INVAL = "Invalid argument", 30 | NFILE = "Too many open files in system", 31 | MFILE = "Too many open files", 32 | NOTTY = "Inappropriate ioctl for device", 33 | TXTBSY = "Text file busy", 34 | FBIG = "File too large", 35 | NOSPC = "No space left on device", 36 | SPIPE = "Illegal seek", 37 | ROFS = "Read-only file system", 38 | MLINK = "Too many links", 39 | PIPE = "Broken pipe", 40 | DOM = "Numerical argument out of domain", 41 | RANGE = "Result too large", 42 | AGAIN = "Resource temporarily unavailable", 43 | INPROGRESS = "Operation now in progress", 44 | ALREADY = "Operation already in progress", 45 | NOTSOCK = "Socket operation on non-socket", 46 | DESTADDRREQ = "Destination address required", 47 | MSGSIZE = "Message too long", 48 | PROTOTYPE = "Protocol wrong type for socket", 49 | NOPROTOOPT = "Protocol not available", 50 | PROTONOSUPPORT = "Protocol not supported", 51 | SOCKTNOSUPPORT = "Socket type not supported", 52 | OPNOTSUPP = "Operation not supported", 53 | PFNOSUPPORT = "Protocol family not supported", 54 | AFNOSUPPORT = "Address family not supported by protocol family", 55 | ADDRINUSE = "Address already in use", 56 | ADDRNOTAVAIL = "Can't assign requested address", 57 | NETDOWN = "Network is down", 58 | NETUNREACH = "Network is unreachable", 59 | NETRESET = "Network dropped connection on reset", 60 | CONNABORTED = "Software caused connection abort", 61 | CONNRESET = "Connection reset by peer", 62 | NOBUFS = "No buffer space available", 63 | ISCONN = "Socket is already connected", 64 | NOTCONN = "Socket is not connected", 65 | SHUTDOWN = "Can't send after socket shutdown", 66 | TOOMANYREFS = "Too many references: can't splice", 67 | TIMEDOUT = "Operation timed out", 68 | CONNREFUSED = "Connection refused", 69 | LOOP = "Too many levels of symbolic links", 70 | NAMETOOLONG = "File name too long", 71 | HOSTDOWN = "Host is down", 72 | HOSTUNREACH = "No route to host", 73 | NOTEMPTY = "Directory not empty", 74 | PROCLIM = "Too many processes", 75 | USERS = "Too many users", 76 | DQUOT = "Disc quota exceeded", 77 | STALE = "Stale NFS file handle", 78 | REMOTE = "Too many levels of remote in path", 79 | BADRPC = "RPC struct is bad", 80 | RPCMISMATCH = "RPC version wrong", 81 | PROGUNAVAIL = "RPC prog. not avail", 82 | PROGMISMATCH = "Program version wrong", 83 | PROCUNAVAIL = "Bad procedure for program", 84 | NOLCK = "No locks available", 85 | NOSYS = "Function not implemented", 86 | FTYPE = "Inappropriate file type or format", 87 | AUTH = "Authentication error", 88 | NEEDAUTH = "Need authenticator", 89 | IPSEC = "IPsec processing failure", 90 | NOATTR = "Attribute not found", 91 | ILSEQ = "Illegal byte sequence", 92 | NOMEDIUM = "No medium found", 93 | MEDIUMTYPE = "Wrong Medium Type", 94 | OVERFLOW = "Conversion overflow", 95 | CANCELED = "Operation canceled", 96 | IDRM = "Identifier removed", 97 | NOMSG = "No message of desired type", 98 | NOTSUP = "Not supported", 99 | } 100 | 101 | return errors 102 | 103 | -------------------------------------------------------------------------------- /rockspec/ljsyscall-0.7-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "ljsyscall" 2 | version = "0.7-1" 3 | source = 4 | { 5 | url = "https://github.com/justincormack/ljsyscall/archive/v0.7.tar.gz"; 6 | dir = "ljsyscall-0.7"; 7 | } 8 | description = 9 | { 10 | summary = "LuaJIT Linux syscall FFI"; 11 | homepage = "http://www.myriabit.com/ljsyscall/"; 12 | license = "MIT"; 13 | } 14 | dependencies = 15 | { 16 | "lua == 5.1"; -- In fact this should be "luajit >= 2.0.0" 17 | } 18 | build = 19 | { 20 | type = "none"; 21 | install = 22 | { 23 | lua = 24 | { 25 | ["syscall"] = "syscall.lua"; 26 | ["syscall.abi"] = "syscall/abi.lua"; 27 | ["syscall.helpers"] = "syscall/helpers.lua"; 28 | ["syscall.syscalls"] = "syscall/syscalls.lua"; 29 | ["syscall.ffifunctions"] = "syscall/ffifunctions.lua"; 30 | ["syscall.types"] = "syscall/types.lua"; 31 | ["syscall.sharedtypes"] = "syscall/sharedtypes.lua"; 32 | ["syscall.features"] = "syscall/features.lua"; 33 | ["syscall.libc"] = "syscall/libc.lua"; 34 | ["syscall.methods"] = "syscall/methods.lua"; 35 | ["syscall.ffitypes"] = "syscall/ffitypes.lua"; 36 | 37 | ["syscall.linux.syscalls"] = "syscall/linux/syscalls.lua"; 38 | ["syscall.linux.c"] = "syscall/linux/c.lua"; 39 | ["syscall.linux.constants"] = "syscall/linux/constants.lua"; 40 | ["syscall.linux.ffitypes"] = "syscall/linux/ffitypes.lua"; 41 | ["syscall.linux.ffifunctions"] = "syscall/linux/ffifunctions.lua"; 42 | ["syscall.linux.ioctl"] = "syscall/linux/ioctl.lua"; 43 | ["syscall.linux.types"] = "syscall/linux/types.lua"; 44 | ["syscall.linux.fcntl"] = "syscall/linux/fcntl.lua"; 45 | ["syscall.linux.errors"] = "syscall/linux/errors.lua"; 46 | 47 | ["syscall.linux.nl"] = "syscall/linux/nl.lua"; 48 | ["syscall.linux.netfilter"] = "syscall/linux/netfilter.lua"; 49 | ["syscall.linux.util"] = "syscall/linux/util.lua"; 50 | 51 | ["syscall.linux.arm.constants"] = "syscall/linux/arm/constants.lua"; 52 | ["syscall.linux.arm.ffitypes"] = "syscall/linux/arm/ffitypes.lua"; 53 | ["syscall.linux.arm.ioctl"] = "syscall/linux/arm/ioctl.lua"; 54 | ["syscall.linux.mips.constants"] = "syscall/linux/mips/constants.lua"; 55 | ["syscall.linux.ppc.constants"] = "syscall/linux/ppc/constants.lua"; 56 | ["syscall.linux.ppc.ffitypes"] = "syscall/linux/ppc/ffitypes.lua"; 57 | ["syscall.linux.ppc.ioctl"] = "syscall/linux/ppc/ioctl.lua"; 58 | ["syscall.linux.x64.constants"] = "syscall/linux/x64/constants.lua"; 59 | ["syscall.linux.x64.ffitypes"] = "syscall/linux/x64/ffitypes.lua"; 60 | ["syscall.linux.x86.constants"] = "syscall/linux/x86/constants.lua"; 61 | ["syscall.linux.x86.ffitypes"] = "syscall/linux/x86/ffitypes.lua"; 62 | 63 | ["syscall.netbsd.syscalls"] = "syscall/netbsd/syscalls.lua"; 64 | ["syscall.netbsd.c"] = "syscall/netbsd/c.lua"; 65 | ["syscall.netbsd.constants"] = "syscall/netbsd/constants.lua"; 66 | ["syscall.netbsd.ffitypes"] = "syscall/netbsd/ffitypes.lua"; 67 | ["syscall.netbsd.ffifunctions"] = "syscall/netbsd/ffifunctions.lua"; 68 | ["syscall.netbsd.ioctl"] = "syscall/netbsd/ioctl.lua"; 69 | ["syscall.netbsd.types"] = "syscall/netbsd/types.lua"; 70 | ["syscall.netbsd.fcntl"] = "syscall/netbsd/fcntl.lua"; 71 | ["syscall.netbsd.errors"] = "syscall/netbsd/errors.lua"; 72 | 73 | ["syscall.osx.syscalls"] = "syscall/osx/syscalls.lua"; 74 | ["syscall.osx.c"] = "syscall/osx/c.lua"; 75 | ["syscall.osx.constants"] = "syscall/osx/constants.lua"; 76 | ["syscall.osx.ffitypes"] = "syscall/osx/ffitypes.lua"; 77 | ["syscall.osx.ffifunctions"] = "syscall/osx/ffifunctions.lua"; 78 | ["syscall.osx.ioctl"] = "syscall/osx/ioctl.lua"; 79 | ["syscall.osx.types"] = "syscall/osx/types.lua"; 80 | ["syscall.osx.fcntl"] = "syscall/osx/fcntl.lua"; 81 | ["syscall.osx.errors"] = "syscall/osx/errors.lua"; 82 | 83 | ["syscall.rump.init"] = "syscall/rump/init.lua"; 84 | ["syscall.rump.c"] = "syscall/rump/c.lua"; 85 | ["syscall.rump.types"] = "syscall/rump/types.lua"; 86 | }; 87 | }; 88 | } 89 | -------------------------------------------------------------------------------- /syscall/netbsd/errors.lua: -------------------------------------------------------------------------------- 1 | -- NetBSD error messages 2 | 3 | return { 4 | PERM = "Operation not permitted", 5 | NOENT = "No such file or directory", 6 | SRCH = "No such process", 7 | INTR = "Interrupted system call", 8 | IO = "Input/output error", 9 | NXIO = "Device not configured", 10 | ["2BIG"] = "Argument list too long", 11 | NOEXEC = "Exec format error", 12 | BADF = "Bad file descriptor", 13 | CHILD = "No child processes", 14 | DEADLK = "Resource deadlock avoided", 15 | NOMEM = "Cannot allocate memory", 16 | ACCES = "Permission denied", 17 | FAULT = "Bad address", 18 | NOTBLK = "Block device required", 19 | BUSY = "Device busy", 20 | EXIST = "File exists", 21 | XDEV = "Cross-device link", 22 | NODEV = "Operation not supported by device", 23 | NOTDIR = "Not a directory", 24 | ISDIR = "Is a directory", 25 | INVAL = "Invalid argument", 26 | NFILE = "Too many open files in system", 27 | MFILE = "Too many open files", 28 | NOTTY = "Inappropriate ioctl for device", 29 | TXTBSY = "Text file busy", 30 | FBIG = "File too large", 31 | NOSPC = "No space left on device", 32 | SPIPE = "Illegal seek", 33 | ROFS = "Read-only file system", 34 | MLINK = "Too many links", 35 | PIPE = "Broken pipe", 36 | DOM = "Numerical argument out of domain", 37 | RANGE = "Result too large or too small", 38 | AGAIN = "Resource temporarily unavailable", 39 | INPROGRESS = "Operation now in progress", 40 | ALREADY = "Operation already in progress", 41 | NOTSOCK = "Socket operation on non-socket", 42 | DESTADDRREQ = "Destination address required", 43 | MSGSIZE = "Message too long", 44 | PROTOTYPE = "Protocol wrong type for socket", 45 | NOPROTOOPT = "Protocol option not available", 46 | PROTONOSUPPORT = "Protocol not supported", 47 | SOCKTNOSUPPORT = "Socket type not supported", 48 | OPNOTSUPP = "Operation not supported", 49 | PFNOSUPPORT = "Protocol family not supported", 50 | AFNOSUPPORT = "Address family not supported by protocol family", 51 | ADDRINUSE = "Address already in use", 52 | ADDRNOTAVAIL = "Can't assign requested address", 53 | NETDOWN = "Network is down", 54 | NETUNREACH = "Network is unreachable", 55 | NETRESET = "Network dropped connection on reset", 56 | CONNABORTED = "Software caused connection abort", 57 | CONNRESET = "Connection reset by peer", 58 | NOBUFS = "No buffer space available", 59 | ISCONN = "Socket is already connected", 60 | NOTCONN = "Socket is not connected", 61 | SHUTDOWN = "Can't send after socket shutdown", 62 | TOOMANYREFS = "Too many references: can't splice", 63 | TIMEDOUT = "Connection timed out", 64 | CONNREFUSED = "Connection refused", 65 | LOOP = "Too many levels of symbolic links", 66 | NAMETOOLONG = "File name too long", 67 | HOSTDOWN = "Host is down", 68 | HOSTUNREACH = "No route to host", 69 | NOTEMPTY = "Directory not empty", 70 | PROCLIM = "Too many processes", 71 | USERS = "Too many users", 72 | DQUOT = "Disc quota exceeded", 73 | STALE = "Stale NFS file handle", 74 | REMOTE = "Too many levels of remote in path", 75 | BADRPC = "RPC struct is bad", 76 | RPCMISMATCH = "RPC version wrong", 77 | PROGUNAVAIL = "RPC prog. not avail", 78 | PROGMISMATCH = "Program version wrong", 79 | PROCUNAVAIL = "Bad procedure for program", 80 | NOLCK = "No locks available", 81 | NOSYS = "Function not implemented", 82 | FTYPE = "Inappropriate file type or format", 83 | AUTH = "Authentication error", 84 | NEEDAUTH = "Need authenticator", 85 | IDRM = "Identifier removed", 86 | NOMSG = "No message of desired type", 87 | OVERFLOW = "Value too large to be stored in data type", 88 | ILSEQ = "Illegal byte sequence", 89 | NOTSUP = "Not supported", 90 | CANCELED = "Operation Canceled", 91 | BADMSG = "Bad or Corrupt message", 92 | NODATA = "No message available", 93 | NOSR = "No STREAM resources", 94 | NOSTR = "Not a STREAM", 95 | TIME = "STREAM ioctl timeout", 96 | NOATTR = "Attribute not found", 97 | MULTIHOP = "Multihop attempted", 98 | NOLINK = "Link has been severed", 99 | PROTO = "Protocol error", 100 | } 101 | 102 | -------------------------------------------------------------------------------- /syscall/freebsd/errors.lua: -------------------------------------------------------------------------------- 1 | -- FreeBSD error messages 2 | 3 | local require = require 4 | 5 | local version = require "syscall.freebsd.version".version 6 | 7 | local errors = { 8 | PERM = "Operation not permitted", 9 | NOENT = "No such file or directory", 10 | SRCH = "No such process", 11 | INTR = "Interrupted system call", 12 | IO = "Input/output error", 13 | NXIO = "Device not configured", 14 | ["2BIG"] = "Argument list too long", 15 | NOEXEC = "Exec format error", 16 | BADF = "Bad file descriptor", 17 | CHILD = "No child processes", 18 | DEADLK = "Resource deadlock avoided", 19 | NOMEM = "Cannot allocate memory", 20 | ACCES = "Permission denied", 21 | FAULT = "Bad address", 22 | NOTBLK = "Block device required", 23 | BUSY = "Resource busy", 24 | EXIST = "File exists", 25 | XDEV = "Cross-device link", 26 | NODEV = "Operation not supported by device", 27 | NOTDIR = "Not a directory", 28 | ISDIR = "Is a directory", 29 | INVAL = "Invalid argument", 30 | NFILE = "Too many open files in system", 31 | MFILE = "Too many open files", 32 | NOTTY = "Inappropriate ioctl for device", 33 | TXTBSY = "Text file busy", 34 | FBIG = "File too large", 35 | NOSPC = "No space left on device", 36 | SPIPE = "Illegal seek", 37 | ROFS = "Read-only file system", 38 | MLINK = "Too many links", 39 | PIPE = "Broken pipe", 40 | DOM = "Numerical argument out of domain", 41 | RANGE = "Result too large", 42 | AGAIN = "Resource temporarily unavailable", 43 | INPROGRESS = "Operation now in progress", 44 | ALREADY = "Operation already in progress", 45 | NOTSOCK = "Socket operation on non-socket", 46 | DESTADDRREQ = "Destination address required", 47 | MSGSIZE = "Message too long", 48 | PROTOTYPE = "Protocol wrong type for socket", 49 | NOPROTOOPT = "Protocol not available", 50 | PROTONOSUPPORT = "Protocol not supported", 51 | SOCKTNOSUPPORT = "Socket type not supported", 52 | OPNOTSUPP = "Operation not supported", 53 | PFNOSUPPORT = "Protocol family not supported", 54 | AFNOSUPPORT = "Address family not supported by protocol family", 55 | ADDRINUSE = "Address already in use", 56 | ADDRNOTAVAIL = "Can't assign requested address", 57 | NETDOWN = "Network is down", 58 | NETUNREACH = "Network is unreachable", 59 | NETRESET = "Network dropped connection on reset", 60 | CONNABORTED = "Software caused connection abort", 61 | CONNRESET = "Connection reset by peer", 62 | NOBUFS = "No buffer space available", 63 | ISCONN = "Socket is already connected", 64 | NOTCONN = "Socket is not connected", 65 | SHUTDOWN = "Can't send after socket shutdown", 66 | TOOMANYREFS = "Too many references: can't splice", 67 | TIMEDOUT = "Operation timed out", 68 | CONNREFUSED = "Connection refused", 69 | LOOP = "Too many levels of symbolic links", 70 | NAMETOOLONG = "File name too long", 71 | HOSTDOWN = "Host is down", 72 | HOSTUNREACH = "No route to host", 73 | NOTEMPTY = "Directory not empty", 74 | PROCLIM = "Too many processes", 75 | USERS = "Too many users", 76 | DQUOT = "Disc quota exceeded", 77 | STALE = "Stale NFS file handle", 78 | REMOTE = "Too many levels of remote in path", 79 | BADRPC = "RPC struct is bad", 80 | RPCMISMATCH = "RPC version wrong", 81 | PROGUNAVAIL = "RPC prog. not avail", 82 | PROGMISMATCH = "Program version wrong", 83 | PROCUNAVAIL = "Bad procedure for program", 84 | NOLCK = "No locks available", 85 | NOSYS = "Function not implemented", 86 | FTYPE = "Inappropriate file type or format", 87 | AUTH = "Authentication error", 88 | NEEDAUTH = "Need authenticator", 89 | IDRM = "Identifier removed", 90 | NOMSG = "No message of desired type", 91 | OVERFLOW = "Value too large to be stored in data type", 92 | CANCELED = "Operation canceled", 93 | ILSEQ = "Illegal byte sequence", 94 | NOATTR = "Attribute not found", 95 | DOOFUS = "Programming error", 96 | BADMSG = "Bad message", 97 | MULTIHOP = "Multihop attempted", 98 | NOLINK = "Link has been severed", 99 | PROTO = "Protocol error", 100 | NOTCAPABLE = "Capabilities insufficient", 101 | CAPMODE = "Not permitted in capability mode", 102 | } 103 | 104 | if version >= 10 then 105 | errors.NOTRECOVERABLE = "State not recoverable" 106 | errors.OWNERDEAD = "Previous owner died" 107 | end 108 | 109 | return errors 110 | 111 | -------------------------------------------------------------------------------- /syscall/openbsd/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- ioctls, filling in as needed 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(types) 11 | 12 | local s, t = types.s, types.t 13 | 14 | local strflag = require("syscall.helpers").strflag 15 | local bit = require "syscall.bit" 16 | 17 | local band = bit.band 18 | local function bor(...) 19 | local r = bit.bor(...) 20 | if r < 0 then r = r + 4294967296 end -- TODO see note in NetBSD 21 | return r 22 | end 23 | local lshift = bit.lshift 24 | local rshift = bit.rshift 25 | 26 | local IOC = { 27 | VOID = 0x20000000, 28 | OUT = 0x40000000, 29 | IN = 0x80000000, 30 | PARM_SHIFT = 13, 31 | } 32 | 33 | IOC.PARM_MASK = lshift(1, IOC.PARM_SHIFT) - 1 34 | IOC.INOUT = IOC.IN + IOC.OUT 35 | IOC.DIRMASK = IOC.IN + IOC.OUT + IOC.VOID 36 | 37 | local function ioc(dir, ch, nr, size) 38 | return t.ulong(bor(dir, 39 | lshift(band(size, IOC.PARM_MASK), 16), 40 | lshift(ch, 8), 41 | nr)) 42 | end 43 | 44 | local singletonmap = { 45 | int = "int1", 46 | char = "char1", 47 | uint = "uint1", 48 | uint64 = "uint64_1", 49 | off = "off1", 50 | } 51 | 52 | local function _IOC(dir, ch, nr, tp) 53 | if type(ch) == "string" then ch = ch:byte() end 54 | if type(tp) == "number" then return ioc(dir, ch, nr, tp) end 55 | local size = s[tp] 56 | local singleton = singletonmap[tp] ~= nil 57 | tp = singletonmap[tp] or tp 58 | return {number = ioc(dir, ch, nr, size), 59 | read = dir == IOC.OUT or dir == IOC.INOUT, write = dir == IOC.IN or dir == IOC.INOUT, 60 | type = t[tp], singleton = singleton} 61 | end 62 | 63 | local _IO = function(ch, nr) return _IOC(IOC.VOID, ch, nr, 0) end 64 | local _IOR = function(ch, nr, tp) return _IOC(IOC.OUT, ch, nr, tp) end 65 | local _IOW = function(ch, nr, tp) return _IOC(IOC.IN, ch, nr, tp) end 66 | local _IOWR = function(ch, nr, tp) return _IOC(IOC.INOUT, ch, nr, tp) end 67 | 68 | local ioctl = strflag { 69 | -- tty ioctls 70 | TIOCEXCL = _IO('t', 13), 71 | TIOCNXCL = _IO('t', 14), 72 | TIOCFLUSH = _IOW('t', 16, "int"), 73 | TIOCGETA = _IOR('t', 19, "termios"), 74 | TIOCSETA = _IOW('t', 20, "termios"), 75 | TIOCSETAW = _IOW('t', 21, "termios"), 76 | TIOCSETAF = _IOW('t', 22, "termios"), 77 | TIOCGETD = _IOR('t', 26, "int"), 78 | TIOCSETD = _IOW('t', 27, "int"), 79 | TIOCDRAIN = _IO('t', 94), 80 | TIOCSIG = _IOW('t', 95, "int"), 81 | TIOCEXT = _IOW('t', 96, "int"), 82 | TIOCSCTTY = _IO('t', 97), 83 | TIOCCONS = _IOW('t', 98, "int"), 84 | TIOCSTAT = _IOW('t', 101, "int"), 85 | TIOCUCNTL = _IOW('t', 102, "int"), 86 | TIOCSWINSZ = _IOW('t', 103, "winsize"), 87 | TIOCGWINSZ = _IOR('t', 104, "winsize"), 88 | TIOCMGET = _IOR('t', 106, "int"), 89 | TIOCMBIC = _IOW('t', 107, "int"), 90 | TIOCMBIS = _IOW('t', 108, "int"), 91 | TIOCMSET = _IOW('t', 109, "int"), 92 | TIOCSTART = _IO('t', 110), 93 | TIOCSTOP = _IO('t', 111), 94 | TIOCPKT = _IOW('t', 112, "int"), 95 | TIOCNOTTY = _IO('t', 113), 96 | TIOCSTI = _IOW('t', 114, "char"), 97 | TIOCOUTQ = _IOR('t', 115, "int"), 98 | TIOCSPGRP = _IOW('t', 118, "int"), 99 | TIOCGPGRP = _IOR('t', 119, "int"), 100 | TIOCCDTR = _IO('t', 120), 101 | TIOCSDTR = _IO('t', 121), 102 | TIOCCBRK = _IO('t', 122), 103 | TIOCSBRK = _IO('t', 123), 104 | 105 | -- file descriptor ioctls 106 | FIOCLEX = _IO('f', 1), 107 | FIONCLEX = _IO('f', 2), 108 | FIONREAD = _IOR('f', 127, "int"), 109 | FIONBIO = _IOW('f', 126, "int"), 110 | FIOASYNC = _IOW('f', 125, "int"), 111 | FIOSETOWN = _IOW('f', 124, "int"), 112 | FIOGETOWN = _IOR('f', 123, "int"), 113 | 114 | -- allow user defined ioctls 115 | _IO = _IO, 116 | _IOR = _IOR, 117 | _IOW = _IOW, 118 | _IOWR = _IOWR, 119 | } 120 | 121 | return ioctl 122 | 123 | end 124 | 125 | return {init = init} 126 | 127 | -------------------------------------------------------------------------------- /test/freebsd.lua: -------------------------------------------------------------------------------- 1 | -- BSD specific tests 2 | 3 | local function init(S) 4 | 5 | local helpers = require "test.helpers" 6 | local types = S.types 7 | local c = S.c 8 | local abi = S.abi 9 | 10 | local bit = require "syscall.bit" 11 | local ffi = require "ffi" 12 | 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local assert = helpers.assert 16 | 17 | local function fork_assert(cond, err, ...) -- if we have forked we need to fail in main thread not fork 18 | if not cond then 19 | print(tostring(err)) 20 | print(debug.traceback()) 21 | S.exit("failure") 22 | end 23 | if cond == true then return ... end 24 | return cond, ... 25 | end 26 | 27 | local function assert_equal(...) 28 | collectgarbage("collect") -- force gc, to test for bugs 29 | return assert_equals(...) 30 | end 31 | 32 | local teststring = "this is a test string" 33 | local size = 512 34 | local buf = t.buffer(size) 35 | local tmpfile = "XXXXYYYYZZZ4521" .. S.getpid() 36 | local tmpfile2 = "./666666DDDDDFFFF" .. S.getpid() 37 | local tmpfile3 = "MMMMMTTTTGGG" .. S.getpid() 38 | local longfile = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" .. S.getpid() 39 | local efile = "./tmpexXXYYY" .. S.getpid() .. ".sh" 40 | local largeval = math.pow(2, 33) -- larger than 2^32 for testing 41 | local mqname = "ljsyscallXXYYZZ" .. S.getpid() 42 | 43 | local clean = function() 44 | S.rmdir(tmpfile) 45 | S.unlink(tmpfile) 46 | S.unlink(tmpfile2) 47 | S.unlink(tmpfile3) 48 | S.unlink(longfile) 49 | S.unlink(efile) 50 | end 51 | 52 | local test = {} 53 | 54 | test.freebsd_unix_at = { 55 | teardown = clean, 56 | test_bindat = function() 57 | if not S.bindat then error "skipped" end 58 | local s = assert(S.socket("unix", "stream")) 59 | local sa = t.sockaddr_un(tmpfile) 60 | assert(s:bindat("fdcwd", sa)) 61 | assert(s:close()) 62 | assert(S.unlink(tmpfile)) 63 | end, 64 | test_connectat = function() 65 | if not S.connectat then error "skipped" end 66 | local s1 = assert(S.socket("unix", "stream")) 67 | local sa = t.sockaddr_un(tmpfile) 68 | assert(s1:bindat("fdcwd", sa)) 69 | assert(s1:listen()) 70 | local s2 = assert(S.socket("unix", "stream")) 71 | assert(s2:connectat("fdcwd", sa)) 72 | assert(s1:close()) 73 | assert(S.unlink(tmpfile)) 74 | end, 75 | } 76 | 77 | test.freebsd_shm = { 78 | test_shm_anon = function() 79 | local fd = assert(S.shm_open(c.SHM.ANON, "rdwr, creat")) 80 | assert(fd:truncate(4096)) 81 | assert(fd:close()) 82 | end, 83 | } 84 | 85 | test.freebsd_procdesc = { 86 | test_procdesc = function() 87 | if not S.pdfork then error "skipped" end 88 | local pid, err, pfd = S.pdfork() 89 | if not pid and err.NOSYS then error "skipped" end -- seems to fail on freebsd9 90 | assert(pid, err) 91 | if pid == 0 then -- child 92 | S.pause() 93 | S.exit() 94 | else -- parent 95 | assert_equal(assert(pfd:pdgetpid()), pid) 96 | assert(pfd:pdkill("term")) 97 | local pev = t.pollfds{{fd = pfd, events = "hup"}} -- HUP is process termination 98 | local p = assert(S.poll(pev, -1)) 99 | assert_equal(p, 1) 100 | pfd:close() 101 | end 102 | end, 103 | } 104 | 105 | -- this is available as a patch for Linux, so these tests could be ported 106 | test.capsicum = { 107 | test_cap_sandboxed_not = function() 108 | if not S.cap_sandboxed then error "skipped" end 109 | assert(not S.cap_sandboxed()) 110 | end, 111 | test_cap_enter = function() 112 | if not S.cap_sandboxed then error "skipped" end 113 | assert(not S.cap_sandboxed()) 114 | local pid = assert(S.fork()) 115 | if pid == 0 then -- child 116 | fork_assert(S.cap_enter()) 117 | fork_assert(S.cap_sandboxed()) 118 | local ok, err = S.open("/dev/null", "rdwr") -- all filesystem access should be disallowed 119 | fork_assert(not ok and err.CAPMODE) 120 | S.exit(23) 121 | else -- parent 122 | local rpid, status = assert(S.waitpid(pid)) 123 | assert(status.WIFEXITED, "process should have exited normally") 124 | assert(status.EXITSTATUS == 23, "exit should be 23") 125 | end 126 | assert(not S.cap_sandboxed()) 127 | end, 128 | } 129 | 130 | return test 131 | 132 | end 133 | 134 | return {init = init} 135 | 136 | -------------------------------------------------------------------------------- /syscall/osx/errors.lua: -------------------------------------------------------------------------------- 1 | -- OSX error messages 2 | 3 | return { 4 | PERM = "Operation not permitted", 5 | NOENT = "No such file or directory", 6 | SRCH = "No such process", 7 | INTR = "Interrupted system call", 8 | IO = "Input/output error", 9 | NXIO = "Device not configured", 10 | ["2BIG"] = "Argument list too long", 11 | NOEXEC = "Exec format error", 12 | BADF = "Bad file descriptor", 13 | CHILD = "No child processes", 14 | DEADLK = "Resource deadlock avoided", 15 | NOMEM = "Cannot allocate memory", 16 | ACCES = "Permission denied", 17 | FAULT = "Bad address", 18 | NOTBLK = "Block device required", 19 | BUSY = "Resource busy", 20 | EXIST = "File exists", 21 | XDEV = "Cross-device link", 22 | NODEV = "Operation not supported by device", 23 | NOTDIR = "Not a directory", 24 | ISDIR = "Is a directory", 25 | INVAL = "Invalid argument", 26 | NFILE = "Too many open files in system", 27 | MFILE = "Too many open files", 28 | NOTTY = "Inappropriate ioctl for device", 29 | TXTBSY = "Text file busy", 30 | FBIG = "File too large", 31 | NOSPC = "No space left on device", 32 | SPIPE = "Illegal seek", 33 | ROFS = "Read-only file system", 34 | MLINK = "Too many links", 35 | PIPE = "Broken pipe", 36 | DOM = "Numerical argument out of domain", 37 | RANGE = "Result too large", 38 | AGAIN = "Resource temporarily unavailable", 39 | INPROGRESS = "Operation now in progress", 40 | ALREADY = "Operation already in progress", 41 | NOTSOCK = "Socket operation on non-socket", 42 | DESTADDRREQ = "Destination address required", 43 | MSGSIZE = "Message too long", 44 | PROTOTYPE = "Protocol wrong type for socket", 45 | NOPROTOOPT = "Protocol not available", 46 | PROTONOSUPPORT = "Protocol not supported", 47 | SOCKTNOSUPPORT = "Socket type not supported", 48 | PFNOSUPPORT = "Protocol family not supported", 49 | AFNOSUPPORT = "Address family not supported by protocol family", 50 | ADDRINUSE = "Address already in use", 51 | ADDRNOTAVAIL = "Can't assign requested address", 52 | NETDOWN = "Network is down", 53 | NETUNREACH = "Network is unreachable", 54 | NETRESET = "Network dropped connection on reset", 55 | CONNABORTED = "Software caused connection abort", 56 | CONNRESET = "Connection reset by peer", 57 | NOBUFS = "No buffer space available", 58 | ISCONN = "Socket is already connected", 59 | NOTCONN = "Socket is not connected", 60 | SHUTDOWN = "Can't send after socket shutdown", 61 | TOOMANYREFS = "Too many references: can't splice", 62 | TIMEDOUT = "Operation timed out", 63 | CONNREFUSED = "Connection refused", 64 | LOOP = "Too many levels of symbolic links", 65 | NAMETOOLONG = "File name too long", 66 | HOSTDOWN = "Host is down", 67 | HOSTUNREACH = "No route to host", 68 | NOTEMPTY = "Directory not empty", 69 | PROCLIM = "Too many processes", 70 | USERS = "Too many users", 71 | DQUOT = "Disc quota exceeded", 72 | STALE = "Stale NFS file handle", 73 | REMOTE = "Too many levels of remote in path", 74 | BADRPC = "RPC struct is bad", 75 | RPCMISMATCH = "RPC version wrong", 76 | PROGUNAVAIL = "RPC prog. not avail", 77 | PROGMISMATCH = "Program version wrong", 78 | PROCUNAVAIL = "Bad procedure for program", 79 | NOLCK = "No locks available", 80 | NOSYS = "Function not implemented", 81 | FTYPE = "Inappropriate file type or format", 82 | AUTH = "Authentication error", 83 | NEEDAUTH = "Need authenticator", 84 | OVERFLOW = "Value too large to be stored in data type", 85 | BADEXEC = "Bad executable (or shared library)", 86 | BADARCH = "Bad CPU type in executable", 87 | SHLIBVERS = "Shared library version mismatch", 88 | BADMACHO = "Malformed Mach-o file", 89 | CANCELED = "Operation canceled", 90 | IDRM = "Identifier removed", 91 | NOMSG = "No message of desired type", 92 | ILSEQ = "Illegal byte sequence", 93 | NOATTR = "Attribute not found", 94 | BADMSG = "Bad message", 95 | MULTIHOP = "EMULTIHOP (Reserved)", 96 | NODATA = "No message available on STREAM", 97 | NOLINK = "ENOLINK (Reserved)", 98 | NOSR = "No STREAM resources", 99 | NOSTR = "Not a STREAM", 100 | PROTO = "Protocol error", 101 | TIME = "STREAM ioctl timeout", 102 | OPNOTSUPP = "Operation not supported on socket", 103 | NOPOLICY = "Policy not found", 104 | NOTRECOVERABLE = "State not recoverable", 105 | OWNERDEAD = "Previous owner died", 106 | QFULL = "Interface output queue is full", 107 | } 108 | 109 | -------------------------------------------------------------------------------- /rockspec/ljsyscall-0.8-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "ljsyscall" 2 | version = "0.8-1" 3 | source = 4 | { 5 | url = "https://github.com/justincormack/ljsyscall/archive/v0.8.tar.gz"; 6 | dir = "ljsyscall-0.8"; 7 | } 8 | description = 9 | { 10 | summary = "LuaJIT Linux syscall FFI"; 11 | homepage = "http://www.myriabit.com/ljsyscall/"; 12 | license = "MIT"; 13 | } 14 | dependencies = 15 | { 16 | "lua == 5.1"; -- In fact this should be "luajit >= 2.0.0" 17 | } 18 | build = 19 | { 20 | type = "none"; 21 | install = 22 | { 23 | lua = 24 | { 25 | ["syscall"] = "syscall.lua"; 26 | ["syscall.abi"] = "syscall/abi.lua"; 27 | ["syscall.helpers"] = "syscall/helpers.lua"; 28 | ["syscall.syscalls"] = "syscall/syscalls.lua"; 29 | ["syscall.ffifunctions"] = "syscall/ffifunctions.lua"; 30 | ["syscall.types"] = "syscall/types.lua"; 31 | ["syscall.sharedtypes"] = "syscall/sharedtypes.lua"; 32 | ["syscall.features"] = "syscall/features.lua"; 33 | ["syscall.libc"] = "syscall/libc.lua"; 34 | ["syscall.methods"] = "syscall/methods.lua"; 35 | ["syscall.ffitypes"] = "syscall/ffitypes.lua"; 36 | ["syscall.util"] = "syscall/util.lua"; 37 | ["syscall.compat"] = "syscall/compat.lua"; 38 | 39 | ["syscall.linux.syscalls"] = "syscall/linux/syscalls.lua"; 40 | ["syscall.linux.c"] = "syscall/linux/c.lua"; 41 | ["syscall.linux.constants"] = "syscall/linux/constants.lua"; 42 | ["syscall.linux.ffitypes"] = "syscall/linux/ffitypes.lua"; 43 | ["syscall.linux.ffifunctions"] = "syscall/linux/ffifunctions.lua"; 44 | ["syscall.linux.ioctl"] = "syscall/linux/ioctl.lua"; 45 | ["syscall.linux.types"] = "syscall/linux/types.lua"; 46 | ["syscall.linux.fcntl"] = "syscall/linux/fcntl.lua"; 47 | ["syscall.linux.errors"] = "syscall/linux/errors.lua"; 48 | ["syscall.linux.compat"] = "syscall/linux/compat.lua"; 49 | ["syscall.linux.util"] = "syscall/linux/util.lua"; 50 | 51 | ["syscall.linux.nl"] = "syscall/linux/nl.lua"; 52 | ["syscall.linux.netfilter"] = "syscall/linux/netfilter.lua"; 53 | ["syscall.linux.sockopt"] = "syscall/linux/sockopt.lua"; 54 | ["syscall.linux.cgroup"] = "syscall/linux/cgroup.lua"; 55 | 56 | ["syscall.linux.arm.constants"] = "syscall/linux/arm/constants.lua"; 57 | ["syscall.linux.arm.ffitypes"] = "syscall/linux/arm/ffitypes.lua"; 58 | ["syscall.linux.arm.ioctl"] = "syscall/linux/arm/ioctl.lua"; 59 | ["syscall.linux.mips.constants"] = "syscall/linux/mips/constants.lua"; 60 | ["syscall.linux.mips.ffitypes"] = "syscall/linux/mips/ffitypes.lua"; 61 | ["syscall.linux.ppc.constants"] = "syscall/linux/ppc/constants.lua"; 62 | ["syscall.linux.ppc.ffitypes"] = "syscall/linux/ppc/ffitypes.lua"; 63 | ["syscall.linux.ppc.ioctl"] = "syscall/linux/ppc/ioctl.lua"; 64 | ["syscall.linux.x64.constants"] = "syscall/linux/x64/constants.lua"; 65 | ["syscall.linux.x64.ffitypes"] = "syscall/linux/x64/ffitypes.lua"; 66 | ["syscall.linux.x86.constants"] = "syscall/linux/x86/constants.lua"; 67 | ["syscall.linux.x86.ffitypes"] = "syscall/linux/x86/ffitypes.lua"; 68 | 69 | ["syscall.netbsd.syscalls"] = "syscall/netbsd/syscalls.lua"; 70 | ["syscall.netbsd.c"] = "syscall/netbsd/c.lua"; 71 | ["syscall.netbsd.constants"] = "syscall/netbsd/constants.lua"; 72 | ["syscall.netbsd.ffitypes"] = "syscall/netbsd/ffitypes.lua"; 73 | ["syscall.netbsd.ffifunctions"] = "syscall/netbsd/ffifunctions.lua"; 74 | ["syscall.netbsd.ioctl"] = "syscall/netbsd/ioctl.lua"; 75 | ["syscall.netbsd.types"] = "syscall/netbsd/types.lua"; 76 | ["syscall.netbsd.fcntl"] = "syscall/netbsd/fcntl.lua"; 77 | ["syscall.netbsd.errors"] = "syscall/netbsd/errors.lua"; 78 | ["syscall.netbsd.util"] = "syscall/netbsd/util.lua"; 79 | 80 | ["syscall.osx.syscalls"] = "syscall/osx/syscalls.lua"; 81 | ["syscall.osx.c"] = "syscall/osx/c.lua"; 82 | ["syscall.osx.constants"] = "syscall/osx/constants.lua"; 83 | ["syscall.osx.ffitypes"] = "syscall/osx/ffitypes.lua"; 84 | ["syscall.osx.ffifunctions"] = "syscall/osx/ffifunctions.lua"; 85 | ["syscall.osx.ioctl"] = "syscall/osx/ioctl.lua"; 86 | ["syscall.osx.types"] = "syscall/osx/types.lua"; 87 | ["syscall.osx.fcntl"] = "syscall/osx/fcntl.lua"; 88 | ["syscall.osx.errors"] = "syscall/osx/errors.lua"; 89 | ["syscall.osx.util"] = "syscall/osx/util.lua"; 90 | 91 | ["syscall.rump.init"] = "syscall/rump/init.lua"; 92 | ["syscall.rump.c"] = "syscall/rump/c.lua"; 93 | ["syscall.rump.types"] = "syscall/rump/types.lua"; 94 | }; 95 | }; 96 | } 97 | -------------------------------------------------------------------------------- /examples/lxc.lua: -------------------------------------------------------------------------------- 1 | -- Work in progress - not complete or tested yet 2 | 3 | -- script to run init.lua in a container for testing 4 | 5 | -- creates a container and runs init in it, innit. 6 | 7 | -- pushes an interface into the container, but only with local routing, not bridged or mac-vlan'd for now 8 | 9 | -- run as root 10 | 11 | local oldassert = assert 12 | local function assert(c, s) 13 | return oldassert(c, tostring(s)) 14 | end 15 | 16 | local S = require "syscall" 17 | local nl = require "syscall.nl" 18 | local util = require "syscall.util" 19 | 20 | local root = arg[1] or "root" 21 | 22 | local init = util.mapfile("init.lua") 23 | local luajit = util.mapfile("luajit/luajit") 24 | local libc = util.mapfile("luajit/libc.so") 25 | local libgcc = util.mapfile("luajit/libgcc_s.so") 26 | 27 | if S.stat(root) then 28 | assert(util.rm(root)) 29 | end 30 | assert(S.mkdir(root, "rwxu")) 31 | 32 | assert(S.mkdir(root .. "/dev", "rwxu")) 33 | assert(S.mkdir(root .. "/dev/pts", "rwxu")) 34 | assert(S.mkdir(root .. "/sbin", "rwxu")) 35 | assert(S.mkdir(root .. "/proc", "rwxu")) 36 | assert(S.mkdir(root .. "/bin", "rwxu")) 37 | assert(S.mkdir(root .. "/root", "rwxu")) 38 | assert(S.mkdir(root .. "/tmp", "rwxu")) 39 | assert(S.mkdir(root .. "/etc", "rwxu")) 40 | assert(S.mkdir(root .. "/sys", "rwxu")) 41 | assert(S.mkdir(root .. "/lib", "rwxu")) 42 | assert(S.mkdir(root .. "/lib/syscall", "rwxu")) 43 | assert(S.mkdir(root .. "/lib/syscall/x64", "rwxu")) 44 | 45 | -- should just read rockspec! 46 | assert(util.cp("init.lua", root .. "/sbin/init", "rwxu")) 47 | assert(util.cp("luajit/luajit", root .. "/bin/luajit", "rwxu")) 48 | assert(util.cp("luajit/libc.so", root .. "/lib/libc.so", "rwxu")) 49 | assert(util.cp("luajit/libgcc_s.so", root .. "/lib/libgcc_s.so", "rwxu")) 50 | assert(util.cp("/usr/local/share/lua/5.1/syscall.lua", root .. "/lib/syscall.lua", "rwxu")) 51 | assert(util.cp("/usr/local/share/lua/5.1/syscall/headers.lua", root .. "/lib/syscall/headers.lua", "rwxu")) 52 | assert(util.cp("/usr/local/share/lua/5.1/syscall/types.lua", root .. "/lib/syscall/types.lua", "rwxu")) 53 | assert(util.cp("/usr/local/share/lua/5.1/syscall/constants.lua", root .. "/lib/syscall/constants.lua", "rwxu")) 54 | assert(util.cp("/usr/local/share/lua/5.1/syscall/helpers.lua", root .. "/lib/syscall/helpers.lua", "rwxu")) 55 | assert(util.cp("/usr/local/share/lua/5.1/syscall/ioctl.lua", root .. "/lib/syscall/ioctl.lua", "rwxu")) 56 | assert(util.cp("/usr/local/share/lua/5.1/syscall/nl.lua", root .. "/lib/syscall/nl.lua", "rwxu")) 57 | assert(util.cp("/usr/local/share/lua/5.1/syscall/x64/constants.lua", root .. "/lib/syscall/x64/constants.lua", "rwxu")) 58 | 59 | assert(S.symlink("/lib/libc.so", root .. "/lib/ld-musl-x86_64.so.1")) 60 | 61 | assert(S.chdir(root)) 62 | 63 | -- should use random names. Also should gc the veth to cleanup. For now just delete it on entry as this is a demo. 64 | nl.dellink(0, "ifname", "veth0") 65 | assert(nl.create_interface{name = "veth0", type = "veth", peer = {name = "veth1"}}) 66 | local i = nl.interfaces() 67 | assert(i.veth0:up()) 68 | assert(i.veth0:address("10.3.0.1/24")) 69 | 70 | local p = assert(S.clone("newnet,newipc,newns,newpid,newuts")) 71 | 72 | if p ~=0 then -- parent 73 | local i = nl.interfaces() 74 | assert(i.veth1:move_ns(p)) 75 | 76 | assert(S.waitpid(-1, "clone")) 77 | else -- child 78 | 79 | -- wait for interface to appear 80 | local sock = assert(nl.socket("route", {groups = "link"})) 81 | local i = nl.interfaces() 82 | if not i.veth1 then 83 | local m = assert(nl.read(sock)) 84 | assert(m.veth1) 85 | end 86 | sock:close() 87 | i:refresh() 88 | -- rename it to eth0 89 | i.veth1:rename("eth0") 90 | 91 | -- set up file system 92 | -- use chroot for now, change to pivot_root later 93 | assert(S.chroot(".")) 94 | 95 | --[[ 96 | -- something like this for pivot_root 97 | fork_assert(S.mount(tmpfile3, tmpfile3, "none", "bind")) -- to make sure on different mount point 98 | fork_assert(S.mount(tmpfile3, tmpfile3, nil, "private")) 99 | fork_assert(S.chdir(tmpfile3)) 100 | fork_assert(S.mkdir("old")) 101 | fork_assert(S.pivot_root(".", "old")) 102 | fork_assert(S.chdir("/")) 103 | ]] 104 | 105 | local chardevices = { 106 | null = {1, 3}, 107 | zero = {1, 5}, 108 | random = {1, 8}, 109 | urandom = {1, 9}, 110 | } 111 | 112 | for k, v in pairs(chardevices) do 113 | assert(S.mknod("/dev/" .. k, "fchr,rusr,wusr", S.t.device(v[1], v[2]))) 114 | end 115 | 116 | -- call init 117 | assert(S.execve("/sbin/init", {"init"}, {})) 118 | S.exit("failure") 119 | end 120 | -------------------------------------------------------------------------------- /syscall/osx/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- ioctls, filling in as needed 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(types) 11 | 12 | local s, t = types.s, types.t 13 | 14 | local strflag = require("syscall.helpers").strflag 15 | local bit = require "syscall.bit" 16 | 17 | local band = bit.band 18 | local function bor(...) 19 | local r = bit.bor(...) 20 | if r < 0 then r = r + 4294967296 end -- TODO see note in NetBSD 21 | return r 22 | end 23 | local lshift = bit.lshift 24 | local rshift = bit.rshift 25 | 26 | local IOC = { 27 | VOID = 0x20000000, 28 | OUT = 0x40000000, 29 | IN = 0x80000000, 30 | PARM_SHIFT = 13, 31 | } 32 | 33 | IOC.PARM_MASK = lshift(1, IOC.PARM_SHIFT) - 1 34 | IOC.INOUT = IOC.IN + IOC.OUT 35 | IOC.DIRMASK = IOC.IN + IOC.OUT + IOC.VOID 36 | 37 | local function ioc(dir, ch, nr, size) 38 | return t.ulong(bor(dir, 39 | lshift(band(size, IOC.PARM_MASK), 16), 40 | lshift(ch, 8), 41 | nr)) 42 | end 43 | 44 | local singletonmap = { 45 | int = "int1", 46 | char = "char1", 47 | uint = "uint1", 48 | uint64 = "uint64_1", 49 | off = "off1", 50 | } 51 | 52 | local function _IOC(dir, ch, nr, tp) 53 | if type(ch) == "string" then ch = ch:byte() end 54 | if type(tp) == "number" then return ioc(dir, ch, nr, tp) end 55 | local size = s[tp] 56 | local singleton = singletonmap[tp] ~= nil 57 | tp = singletonmap[tp] or tp 58 | return {number = ioc(dir, ch, nr, size), 59 | read = dir == IOC.OUT or dir == IOC.INOUT, write = dir == IOC.IN or dir == IOC.INOUT, 60 | type = t[tp], singleton = singleton} 61 | end 62 | 63 | local _IO = function(ch, nr) return _IOC(IOC.VOID, ch, nr, 0) end 64 | local _IOR = function(ch, nr, tp) return _IOC(IOC.OUT, ch, nr, tp) end 65 | local _IOW = function(ch, nr, tp) return _IOC(IOC.IN, ch, nr, tp) end 66 | local _IOWR = function(ch, nr, tp) return _IOC(IOC.INOUT, ch, nr, tp) end 67 | local _IOWINT = function(ch, nr) return _IOC(IOC.VOID, ch, nr, "int") end 68 | 69 | local ioctl = strflag { 70 | -- tty ioctls 71 | TIOCEXCL = _IO('t', 13), 72 | TIOCNXCL = _IO('t', 14), 73 | TIOCFLUSH = _IOW('t', 16, "int"), 74 | TIOCGETA = _IOR('t', 19, "termios"), 75 | TIOCSETA = _IOW('t', 20, "termios"), 76 | TIOCSETAW = _IOW('t', 21, "termios"), 77 | TIOCSETAF = _IOW('t', 22, "termios"), 78 | TIOCGETD = _IOR('t', 26, "int"), 79 | TIOCSETD = _IOW('t', 27, "int"), 80 | TIOCPTYUNLK = _IO('t', 82), 81 | TIOCPTYGNAME = _IOC(IOC.OUT, 't', 83, 128), 82 | TIOCPTYGRANT = _IO('t', 84), 83 | TIOCGDRAINWAIT = _IOR('t', 86, "int"), 84 | TIOCSDRAINWAIT = _IOW('t', 87, "int"), 85 | TIOCTIMESTAMP = _IOR('t', 89, "timeval"), 86 | TIOCMGDTRWAIT = _IOR('t', 90, "int"), 87 | TIOCMSDTRWAIT = _IOW('t', 91, "int"), 88 | TIOCDRAIN = _IO('t', 94), 89 | TIOCSIG = _IO('t', 95), 90 | TIOCEXT = _IOW('t', 96, "int"), 91 | TIOCSCTTY = _IO('t', 97), 92 | TIOCCONS = _IOW('t', 98, "int"), 93 | TIOCGSID = _IOR('t', 99, "int"), 94 | TIOCSTAT = _IO('t', 101), 95 | TIOCUCNTL = _IOW('t', 102, "int"), 96 | TIOCSWINSZ = _IOW('t', 103, "winsize"), 97 | TIOCGWINSZ = _IOR('t', 104, "winsize"), 98 | TIOCMGET = _IOR('t', 106, "int"), 99 | TIOCMBIC = _IOW('t', 107, "int"), 100 | TIOCMBIS = _IOW('t', 108, "int"), 101 | TIOCMSET = _IOW('t', 109, "int"), 102 | TIOCSTART = _IO('t', 110), 103 | TIOCSTOP = _IO('t', 111), 104 | TIOCPKT = _IOW('t', 112, "int"), 105 | TIOCNOTTY = _IO('t', 113), 106 | TIOCSTI = _IOW('t', 114, "char"), 107 | TIOCOUTQ = _IOR('t', 115, "int"), 108 | TIOCSPGRP = _IOW('t', 118, "int"), 109 | TIOCGPGRP = _IOR('t', 119, "int"), 110 | TIOCCDTR = _IO('t', 120), 111 | TIOCSDTR = _IO('t', 121), 112 | TIOCCBRK = _IO('t', 122), 113 | TIOCSBRK = _IO('t', 123), 114 | FIOCLEX = _IO('f', 1), 115 | FIONCLEX = _IO('f', 2), 116 | FIONREAD = _IOR('f', 127, "int"), 117 | FIONBIO = _IOW('f', 126, "int"), 118 | FIOASYNC = _IOW('f', 125, "int"), 119 | FIOSETOWN = _IOW('f', 124, "int"), 120 | FIOGETOWN = _IOR('f', 123, "int"), 121 | FIODTYPE = _IOR('f', 122, "int"), 122 | } 123 | 124 | return ioctl 125 | 126 | end 127 | 128 | return {init = init} 129 | 130 | -------------------------------------------------------------------------------- /syscall/netbsd/syscalls.lua: -------------------------------------------------------------------------------- 1 | -- BSD specific syscalls 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local abi = require "syscall.abi" 11 | 12 | return function(S, hh, c, C, types) 13 | 14 | local ffi = require "ffi" 15 | 16 | local errno = ffi.errno 17 | 18 | local t, pt, s = types.t, types.pt, types.s 19 | 20 | local ret64, retnum, retfd, retbool, retptr, retiter = hh.ret64, hh.retnum, hh.retfd, hh.retbool, hh.retptr, hh.retiter 21 | 22 | local h = require "syscall.helpers" 23 | local istype, mktype, getfd = h.istype, h.mktype, h.getfd 24 | local octal = h.octal 25 | 26 | function S.paccept(sockfd, addr, addrlen, set, flags) 27 | if set then set = mktype(t.sigset, set) end 28 | local saddr = pt.sockaddr(addr) 29 | return retfd(C.paccept(getfd(sockfd), saddr, addrlen, set, c.SOCK[flags])) 30 | end 31 | 32 | local mntstruct = { 33 | ffs = t.ufs_args, 34 | --nfs = t.nfs_args, 35 | --mfs = t.mfs_args, 36 | tmpfs = t.tmpfs_args, 37 | sysvbfs = t.ufs_args, 38 | ptyfs = t.ptyfs_args, 39 | procfs = t.procfs_args, 40 | } 41 | 42 | function S.mount(fstype, dir, flags, data, datalen) 43 | local str 44 | if type(data) == "string" then -- common case, for ufs etc 45 | str = data 46 | data = {fspec = pt.char(str)} 47 | end 48 | if data then 49 | local tp = mntstruct[fstype] 50 | if tp then data = mktype(tp, data) end 51 | else 52 | datalen = 0 53 | end 54 | local ret = C.mount(fstype, dir, c.MNT[flags], data, datalen or #data) 55 | return retbool(ret) 56 | end 57 | 58 | function S.reboot(how, bootstr) 59 | return retbool(C.reboot(c.RB[how], bootstr)) 60 | end 61 | 62 | function S.fsync_range(fd, how, start, length) return retbool(C.fsync_range(getfd(fd), c.FSYNC[how], start, length)) end 63 | 64 | function S.getvfsstat(flags, buf, size) -- note order of args as usually leave buf empty 65 | flags = c.VFSMNT[flags or "WAIT"] -- default not zero 66 | if not buf then 67 | local n, err = C.getvfsstat(nil, 0, flags) 68 | if not n then return nil, t.error(err or errno()) end 69 | --buf = t.statvfss(n) -- TODO define 70 | size = s.statvfs * n 71 | end 72 | size = size or #buf 73 | local n, err = C.getvfsstat(buf, size, flags) 74 | if not n then return nil, err end 75 | return buf -- TODO need type with number 76 | end 77 | 78 | -- TODO when we define this for osx can go in common code (curently defined in libc.lua) 79 | function S.getcwd(buf, size) 80 | size = size or c.PATH_MAX 81 | buf = buf or t.buffer(size) 82 | local ret, err = C.getcwd(buf, size) 83 | if ret == -1 then return nil, t.error(err or errno()) end 84 | return ffi.string(buf) 85 | end 86 | 87 | function S.kqueue1(flags) return retfd(C.kqueue1(c.O[flags])) end 88 | 89 | -- TODO this is the same as ppoll other than if timeout is modified, which Linux syscall but not libc does; could merge 90 | function S.pollts(fds, timeout, set) 91 | if timeout then timeout = mktype(t.timespec, timeout) end 92 | if set then set = mktype(t.sigset, set) end 93 | return retnum(C.pollts(fds.pfd, #fds, timeout, set)) 94 | end 95 | 96 | function S.ktrace(tracefile, ops, trpoints, pid) 97 | return retbool(C.ktrace(tracefile, c.KTROP[ops], c.KTRFAC(trpoints, "V2"), pid)) 98 | end 99 | function S.fktrace(fd, ops, trpoints, pid) 100 | return retbool(C.fktrace(getfd(fd), c.KTROP[ops], c.KTRFAC(trpoints, "V2"), pid)) 101 | end 102 | function S.utrace(label, addr, len) 103 | return retbool(C.utrace(label, addr, len)) -- TODO allow string to be passed as addr? 104 | end 105 | 106 | -- pty functions 107 | function S.grantpt(fd) return S.ioctl(fd, "TIOCGRANTPT") end 108 | function S.unlockpt(fd) return 0 end 109 | function S.ptsname(fd) 110 | local pm, err = S.ioctl(fd, "TIOCPTSNAME") 111 | if not pm then return nil, err end 112 | return ffi.string(pm.sn) 113 | end 114 | 115 | -- TODO we need to fix sigaction in NetBSD, syscall seems to have changed to sigaction_tramp 116 | function S.pause() return S.select({}) end -- select on nothing forever 117 | 118 | -- ksem functions. Not very well documented! You shoudl probably use pthreads in most cases 119 | function S.ksem_init(value, semid) 120 | semid = semid or t.intptr1() 121 | local ok, err = C._ksem_init(value, semid) 122 | if not ok then return nil, t.error(err or errno()) end 123 | return semid[0] 124 | end 125 | 126 | function S.ksem_destroy(semid) 127 | return retbool(C._ksem_destroy(semid)) 128 | end 129 | 130 | return S 131 | 132 | end 133 | 134 | -------------------------------------------------------------------------------- /syscall/netbsd/ffifunctions.lua: -------------------------------------------------------------------------------- 1 | -- define system calls for ffi, NetBSD specific calls 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | require "syscall.bsd.ffi" 11 | 12 | local cdef = require "ffi".cdef 13 | 14 | cdef[[ 15 | int fsync_range(int fd, int how, off_t start, off_t length); 16 | int paccept(int s, struct sockaddr *addr, socklen_t *addrlen, const sigset_t *sigmask, int flags); 17 | int reboot(int howto, char *bootstr); 18 | int ioctl(int d, unsigned long request, void *arg); 19 | int getvfsstat(struct statvfs *buf, size_t bufsize, int flags); 20 | int utrace(const char *label, void *addr, size_t len); 21 | int fktrace(int fd, int ops, int trpoints, pid_t pid); 22 | 23 | ssize_t listxattr(const char *path, char *list, size_t size); 24 | ssize_t llistxattr(const char *path, char *list, size_t size); 25 | ssize_t flistxattr(int fd, char *list, size_t size); 26 | ssize_t getxattr(const char *path, const char *name, void *value, size_t size); 27 | ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size); 28 | ssize_t fgetxattr(int fd, const char *name, void *value, size_t size); 29 | int setxattr(const char *path, const char *name, const void *value, size_t size, int flags); 30 | int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags); 31 | int fsetxattr(int fd, const char *name, const void *value, size_t size, int flags); 32 | int removexattr(const char *path, const char *name); 33 | int lremovexattr(const char *path, const char *name); 34 | int fremovexattr(int fd, const char *name); 35 | 36 | int __mount50(const char *type, const char *dir, int flags, void *data, size_t data_len); 37 | int __stat50(const char *path, struct stat *sb); 38 | int __lstat50(const char *path, struct stat *sb); 39 | int __fstat50(int fd, struct stat *sb); 40 | int __getdents30(int fd, char *buf, size_t nbytes); 41 | int __socket30(int domain, int type, int protocol); 42 | int __select50(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 43 | int __pselect50(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); 44 | int __fhopen40(const void *fhp, size_t fh_size, int flags); 45 | int __fhstat50(const void *fhp, size_t fh_size, struct stat *sb); 46 | int __fhstatvfs140(const void *fhp, size_t fh_size, struct statvfs *buf, int flags); 47 | int __getfh30(const char *path, void *fhp, size_t *fh_size); 48 | int __utimes50(const char *path, const struct timeval times[2]); 49 | int __lutimes50(const char *path, const struct timeval times[2]); 50 | int __futimes50(int fd, const struct timeval times[2]); 51 | int __posix_fadvise50(int fd, off_t offset, off_t size, int hint); 52 | int __kevent50(int kq, const struct kevent *changelist, size_t nchanges, struct kevent *eventlist, size_t nevents, const struct timespec *timeout); 53 | int __mknod50(const char *path, mode_t mode, dev_t dev); 54 | int __pollts50(struct pollfd * restrict fds, nfds_t nfds, const struct timespec * restrict ts, const sigset_t * restrict sigmask); 55 | 56 | int __getcwd(char *buf, size_t size); 57 | int __libc_sigaction14(int signum, const struct sigaction *act, struct sigaction *oldact); 58 | 59 | int _ksem_init(unsigned int, intptr_t *); 60 | int _ksem_open(const char *, int, mode_t, unsigned int, intptr_t *); 61 | int _ksem_unlink(const char *); 62 | int _ksem_close(intptr_t); 63 | int _ksem_post(intptr_t); 64 | int _ksem_wait(intptr_t); 65 | int _ksem_trywait(intptr_t); 66 | int _ksem_getvalue(intptr_t, unsigned int *); 67 | int _ksem_destroy(intptr_t); 68 | int _ksem_timedwait(intptr_t, const struct timespec *); 69 | 70 | int __gettimeofday50(struct timeval *tv, void *tz); 71 | int __settimeofday50(const struct timeval *tv, const void *tz); 72 | int __getitimer50(int which, struct itimerval *curr_value); 73 | int __setitimer50(int which, const struct itimerval *new_value, struct itimerval *old_value); 74 | int __clock_getres50(clockid_t clk_id, struct timespec *res); 75 | int __clock_gettime50(clockid_t clk_id, struct timespec *tp); 76 | int __clock_settime50(clockid_t clk_id, const struct timespec *tp); 77 | int __nanosleep50(const struct timespec *req, struct timespec *rem); 78 | int __timer_settime50(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec * old_value); 79 | int __timer_gettime50(timer_t timerid, struct itimerspec *curr_value); 80 | int __adjtime50(const struct timeval *delta, struct timeval *olddelta); 81 | 82 | int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags); 83 | ]] 84 | 85 | -------------------------------------------------------------------------------- /syscall/freebsd/ioctl.lua: -------------------------------------------------------------------------------- 1 | -- ioctls, filling in as needed 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(types) 11 | 12 | local s, t = types.s, types.t 13 | 14 | local strflag = require("syscall.helpers").strflag 15 | local bit = require "syscall.bit" 16 | 17 | local band = bit.band 18 | local function bor(...) 19 | local r = bit.bor(...) 20 | if r < 0 then r = r + 4294967296 end -- TODO see note in NetBSD 21 | return r 22 | end 23 | local lshift = bit.lshift 24 | local rshift = bit.rshift 25 | 26 | local IOC = { 27 | VOID = 0x20000000, 28 | OUT = 0x40000000, 29 | IN = 0x80000000, 30 | PARM_SHIFT = 13, 31 | } 32 | 33 | IOC.PARM_MASK = lshift(1, IOC.PARM_SHIFT) - 1 34 | IOC.INOUT = IOC.IN + IOC.OUT 35 | IOC.DIRMASK = IOC.IN + IOC.OUT + IOC.VOID 36 | 37 | local function ioc(dir, ch, nr, size) 38 | return t.ulong(bor(dir, 39 | lshift(band(size, IOC.PARM_MASK), 16), 40 | lshift(ch, 8), 41 | nr)) 42 | end 43 | 44 | local singletonmap = { 45 | int = "int1", 46 | char = "char1", 47 | uint = "uint1", 48 | uint64 = "uint64_1", 49 | off = "off1", 50 | } 51 | 52 | local function _IOC(dir, ch, nr, tp) 53 | if type(ch) == "string" then ch = ch:byte() end 54 | if type(tp) == "number" then return ioc(dir, ch, nr, tp) end 55 | local size = s[tp] 56 | local singleton = singletonmap[tp] ~= nil 57 | tp = singletonmap[tp] or tp 58 | return {number = ioc(dir, ch, nr, size), 59 | read = dir == IOC.OUT or dir == IOC.INOUT, write = dir == IOC.IN or dir == IOC.INOUT, 60 | type = t[tp], singleton = singleton} 61 | end 62 | 63 | local _IO = function(ch, nr) return _IOC(IOC.VOID, ch, nr, 0) end 64 | local _IOR = function(ch, nr, tp) return _IOC(IOC.OUT, ch, nr, tp) end 65 | local _IOW = function(ch, nr, tp) return _IOC(IOC.IN, ch, nr, tp) end 66 | local _IOWR = function(ch, nr, tp) return _IOC(IOC.INOUT, ch, nr, tp) end 67 | local _IOWINT = function(ch, nr) return _IOC(IOC.VOID, ch, nr, "int") end 68 | 69 | local ioctl = strflag { 70 | -- tty ioctls 71 | TIOCEXCL = _IO('t', 13), 72 | TIOCNXCL = _IO('t', 14), 73 | TIOCGPTN = _IOR('t', 15, "int"), 74 | TIOCFLUSH = _IOW('t', 16, "int"), 75 | TIOCGETA = _IOR('t', 19, "termios"), 76 | TIOCSETA = _IOW('t', 20, "termios"), 77 | TIOCSETAW = _IOW('t', 21, "termios"), 78 | TIOCSETAF = _IOW('t', 22, "termios"), 79 | TIOCGETD = _IOR('t', 26, "int"), 80 | TIOCSETD = _IOW('t', 27, "int"), 81 | TIOCPTMASTER = _IO('t', 28), 82 | TIOCGDRAINWAIT = _IOR('t', 86, "int"), 83 | TIOCSDRAINWAIT = _IOW('t', 87, "int"), 84 | TIOCTIMESTAMP = _IOR('t', 89, "timeval"), 85 | TIOCMGDTRWAIT = _IOR('t', 90, "int"), 86 | TIOCMSDTRWAIT = _IOW('t', 91, "int"), 87 | TIOCDRAIN = _IO('t', 94), 88 | TIOCSIG = _IOWINT('t', 95), 89 | TIOCEXT = _IOW('t', 96, "int"), 90 | TIOCSCTTY = _IO('t', 97), 91 | TIOCCONS = _IOW('t', 98, "int"), 92 | TIOCGSID = _IOR('t', 99, "int"), 93 | TIOCSTAT = _IO('t', 101), 94 | TIOCUCNTL = _IOW('t', 102, "int"), 95 | TIOCSWINSZ = _IOW('t', 103, "winsize"), 96 | TIOCGWINSZ = _IOR('t', 104, "winsize"), 97 | TIOCMGET = _IOR('t', 106, "int"), 98 | TIOCMBIC = _IOW('t', 107, "int"), 99 | TIOCMBIS = _IOW('t', 108, "int"), 100 | TIOCMSET = _IOW('t', 109, "int"), 101 | TIOCSTART = _IO('t', 110), 102 | TIOCSTOP = _IO('t', 111), 103 | TIOCPKT = _IOW('t', 112, "int"), 104 | TIOCNOTTY = _IO('t', 113), 105 | TIOCSTI = _IOW('t', 114, "char"), 106 | TIOCOUTQ = _IOR('t', 115, "int"), 107 | TIOCSPGRP = _IOW('t', 118, "int"), 108 | TIOCGPGRP = _IOR('t', 119, "int"), 109 | TIOCCDTR = _IO('t', 120), 110 | TIOCSDTR = _IO('t', 121), 111 | TIOCCBRK = _IO('t', 122), 112 | TIOCSBRK = _IO('t', 123), 113 | 114 | -- file descriptor ioctls 115 | FIOCLEX = _IO('f', 1), 116 | FIONCLEX = _IO('f', 2), 117 | FIONREAD = _IOR('f', 127, "int"), 118 | FIONBIO = _IOW('f', 126, "int"), 119 | FIOASYNC = _IOW('f', 125, "int"), 120 | FIOSETOWN = _IOW('f', 124, "int"), 121 | FIOGETOWN = _IOR('f', 123, "int"), 122 | FIODTYPE = _IOR('f', 122, "int"), 123 | FIOGETLBA = _IOR('f', 121, "int"), 124 | FIODGNAME = _IOW('f', 120, "fiodgname_arg"), 125 | FIONWRITE = _IOR('f', 119, "int"), 126 | FIONSPACE = _IOR('f', 118, "int"), 127 | FIOSEEKDATA = _IOWR('f', 97, "off"), 128 | FIOSEEKHOLE = _IOWR('f', 98, "off"), 129 | 130 | -- allow user defined ioctls 131 | _IO = _IO, 132 | _IOR = _IOR, 133 | _IOW = _IOW, 134 | _IOWR = _IOWR, 135 | _IOWINT = _IOWINT, 136 | } 137 | 138 | return ioctl 139 | 140 | end 141 | 142 | return {init = init} 143 | 144 | -------------------------------------------------------------------------------- /syscall/netbsd/util.lua: -------------------------------------------------------------------------------- 1 | -- NetBSD utility functions 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(S) 11 | 12 | local abi, types, c = S.abi, S.types, S.c 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local h = require "syscall.helpers" 16 | local divmod = h.divmod 17 | 18 | local ffi = require "ffi" 19 | 20 | local bit = require "syscall.bit" 21 | 22 | local octal = h.octal 23 | 24 | -- TODO move to helpers? see notes in syscall.lua about reworking though 25 | local function istype(tp, x) 26 | if ffi.istype(tp, x) then return x end 27 | return false 28 | end 29 | 30 | local util = {} 31 | 32 | local mt = {} 33 | 34 | -- initial implementation of network ioctls, no real attempt to make it compatible with Linux... 35 | -- initially just implement the ones from rump netconfig, make interface later 36 | 37 | -- it is a bit messy creating new socket every time, better make a sequence of commands 38 | 39 | local function sockioctl(domain, tp, io, data) 40 | local sock, err = S.socket(domain, tp) 41 | if not sock then return nil, err end 42 | local io, err = sock:ioctl(io, data) 43 | sock:close() 44 | if not io then return nil, err end 45 | return io 46 | end 47 | 48 | function util.ifcreate(name) return sockioctl("inet", "dgram", "SIOCIFCREATE", t.ifreq{name = name}) end 49 | function util.ifdestroy(name) return sockioctl("inet", "dgram", "SIOCIFDESTROY", t.ifreq{name = name}) end 50 | function util.ifgetflags(name) 51 | local io, err = sockioctl("inet", "dgram", "SIOCGIFFLAGS", t.ifreq{name = name}) 52 | if not io then return nil, err end 53 | return io.flags 54 | end 55 | function util.ifsetflags(name, flags) 56 | return sockioctl("inet", "dgram", "SIOCSIFFLAGS", {name = name, flags = c.IFF[flags]}) 57 | end 58 | function util.ifup(name) 59 | local flags, err = util.ifgetflags(name) 60 | if not flags then return nil, err end 61 | return util.ifsetflags(name, c.IFF(flags, "up")) 62 | end 63 | function util.ifdown(name) 64 | local flags, err = util.ifgetflags(name) 65 | if not flags then return nil, err end 66 | return util.ifsetflags(name, c.IFF(flags, "~up")) 67 | end 68 | 69 | function util.ifsetlinkstr(name, str) -- used to pass (optional) string to rump virtif (eg name of underlying tap device) 70 | return sockioctl("inet", "dgram", "SIOCSLINKSTR", {name = name, cmd = 0, data = str}) 71 | end 72 | 73 | -- TODO merge into one ifaddr function 74 | function util.ifaddr_inet4(name, addr, mask) 75 | -- TODO this function needs mask as an inaddr, so need to fix this if passed as / format or number 76 | local addr, mask = util.inet_name(addr, mask) 77 | 78 | local bn = addr:get_mask_bcast(mask) 79 | local broadcast, netmask = bn.broadcast, bn.netmask 80 | 81 | local ia = t.ifaliasreq{name = name, addr = addr, mask = netmask, broadaddr = broadcast} 82 | 83 | return sockioctl("inet", "dgram", "SIOCAIFADDR", ia) 84 | end 85 | function util.ifaddr_inet6(name, addr, mask) 86 | local addr, mask = util.inet_name(addr, mask) 87 | assert(ffi.istype(t.in6_addr, addr), "not an ipv6 address") -- TODO remove once merged 88 | 89 | local prefixmask = t.in6_addr() 90 | local bb, b = divmod(mask, 8) 91 | for i = 0, bb - 1 do prefixmask.s6_addr[i] = 0xff end 92 | if bb < 16 then prefixmask.s6_addr[bb] = bit.lshift(0xff, 8 - b) end -- TODO needs test! 93 | 94 | local ia = t.in6_aliasreq{name = name, addr = addr, prefixmask = prefixmask, 95 | lifetime = {pltime = "infinite_lifetime", vltime = "infinite_lifetime"}} 96 | 97 | return sockioctl("inet6", "dgram", "SIOCAIFADDR_IN6", ia) 98 | end 99 | 100 | -- table based mount, more cross OS compatible 101 | function util.mount(tab) 102 | local filesystemtype = tab.type 103 | local dir = tab.target or tab.dir 104 | local flags = tab.flags 105 | local data = tab.data 106 | local datalen = tab.datalen 107 | if tab.fspec then data = tab.fspec end 108 | return S.mount(filesystemtype, dir, flags, data, datalen) 109 | end 110 | 111 | local function kdumpfn(len) 112 | return function(buf, pos) 113 | if pos + s.ktr_header >= len then return nil end 114 | local ktr = pt.ktr_header(buf + pos) 115 | if pos + s.ktr_header + ktr.len >= len then return nil end 116 | return pos + #ktr, ktr 117 | end 118 | end 119 | 120 | function util.kdump(buf, len) 121 | return kdumpfn(len), buf, 0 122 | end 123 | 124 | local function do_bridge_setcmd(name, op, arg) 125 | return sockioctl("inet", "dgram", "SIOCSDRVSPEC", {name = name, cms = op, data = arg}) 126 | end 127 | local function do_bridge_getcmd(name, op, arg) -- TODO should allocate correct arg type here based on arg 128 | local data, err = sockioctl("inet", "dgram", "SIOCGDRVSPEC", {name = name, cms = op, data = arg}) 129 | if not data then return nil, err end 130 | return arg 131 | end 132 | 133 | return util 134 | 135 | end 136 | 137 | return {init = init} 138 | 139 | -------------------------------------------------------------------------------- /syscall/compat.lua: -------------------------------------------------------------------------------- 1 | -- Compatibility wrappers to add more commonality between different systems, plus define common functions from man(3) 2 | 3 | local require, error, assert, tonumber, tostring, 4 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 5 | pcall, type, table, string = 6 | require, error, assert, tonumber, tostring, 7 | setmetatable, pairs, ipairs, unpack, rawget, rawset, 8 | pcall, type, table, string 9 | 10 | local function init(S) 11 | 12 | local abi, types, c = S.abi, S.types, S.c 13 | local t, pt, s = types.t, types.pt, types.s 14 | 15 | local ffi = require "ffi" 16 | 17 | local h = require "syscall.helpers" 18 | 19 | local istype, mktype, getfd = h.istype, h.mktype, h.getfd 20 | 21 | if not S.creat then 22 | function S.creat(pathname, mode) return S.open(pathname, "CREAT,WRONLY,TRUNC", mode) end 23 | end 24 | 25 | function S.nice(inc) 26 | local prio = S.getpriority("process", 0) -- this cannot fail with these args. 27 | local ok, err = S.setpriority("process", 0, prio + inc) 28 | if not ok then return nil, err end 29 | return S.getpriority("process", 0) 30 | end 31 | 32 | -- deprecated in NetBSD and not in some archs for Linux, implement with recvfrom/sendto 33 | function S.recv(fd, buf, count, flags) return S.recvfrom(fd, buf, count, flags, nil, nil) end 34 | function S.send(fd, buf, count, flags) return S.sendto(fd, buf, count, flags, nil, nil) end 35 | 36 | -- not a syscall in many systems, defined in terms of sigaction 37 | local sigret = {} 38 | for k, v in pairs(c.SIGACT) do if k ~= "ERR" then sigret[v] = k end end 39 | 40 | if S.sigaction then 41 | function S.signal(signum, handler) -- defined in terms of sigaction, see portability notes in Linux man page 42 | local oldact = t.sigaction() 43 | local ok, err = S.sigaction(signum, handler, oldact) 44 | if not ok then return nil, err end 45 | local num = tonumber(t.intptr(oldact.handler)) 46 | local ret = sigret[num] 47 | if ret then return ret end -- return eg "IGN", "DFL" not a function pointer 48 | return oldact.handler 49 | end 50 | end 51 | 52 | if not S.pause and S.sigsuspend then -- NetBSD and OSX deprecate pause 53 | function S.pause() return S.sigsuspend(t.sigset()) end 54 | end 55 | 56 | if not S.alarm and S.setitimer then -- usually implemented via itimer, although Linux provides alarm as syscall 57 | function S.alarm(sec) 58 | local oldit, err = S.setitimer(c.ITIMER.REAL, {0, sec}) 59 | if not oldit then return nil, err end -- alarm not supposed to return errors but hey 60 | return oldit.value.sec 61 | end 62 | end 63 | 64 | -- non standard names 65 | if not S.umount then S.umount = S.unmount end 66 | if not S.unmount then S.unmount = S.umount end 67 | 68 | if S.getdirentries and not S.getdents then -- eg OSX has extra arg 69 | function S.getdents(fd, buf, len) 70 | return S.getdirentries(fd, buf, len, nil) 71 | end 72 | end 73 | 74 | -- TODO we should allow utimbuf and also table of times really; this is the very old 1s precision version, NB Linux has syscall 75 | if not S.utime then 76 | function S.utime(path, actime, modtime) 77 | local tv 78 | modtime = modtime or actime 79 | if actime and modtime then tv = {actime, modtime} end 80 | return S.utimes(path, tv) 81 | end 82 | end 83 | 84 | -- not a syscall in Linux 85 | if S.utimensat and not S.futimens then 86 | function S.futimens(fd, times) 87 | return S.utimensat(fd, nil, times, 0) 88 | end 89 | end 90 | 91 | -- some linux arhcitectures eg ARM do not have a time syscall 92 | if not S.time then 93 | function S.time(t) 94 | local tv = S.gettimeofday() 95 | if t then t[0] = tv.sec end 96 | return tv.sec 97 | end 98 | end 99 | 100 | -- the utimes, futimes, lutimes are legacy, but OSX/FreeBSD do not support the nanosecond versions 101 | -- we support the legacy versions but do not fake the more precise ones 102 | S.futimes = S.futimes or S.futimens 103 | if S.utimensat and not S.lutimes then 104 | function S.lutimes(filename, times) 105 | return S.utimensat("FDCWD", filename, times, "SYMLINK_NOFOLLOW") 106 | end 107 | end 108 | if S.utimensat and not S.utimes then 109 | function S.utimes(filename, times) 110 | return S.utimensat("FDCWD", filename, times, 0) 111 | end 112 | end 113 | 114 | if not S.wait then 115 | function S.wait(status) return S.waitpid(-1, 0, status) end 116 | end 117 | 118 | S.wait3 = function(options, rusage, status) return S.wait4(-1, options, rusage, status) end 119 | 120 | if not S.waitpid and S.wait4 then 121 | S.waitpid = function(pid, options, status) return S.wait4(pid, options, false, status) end 122 | end 123 | 124 | if S.wait4 and not S.wait then 125 | S.wait = function(status) return S.wait4(-1, 0, false, status) end 126 | end 127 | 128 | if not S.nanosleep then 129 | function S.nanosleep(req, rem) 130 | S.select({}, req) 131 | if rem then rem.sec, rem.nsec = 0, 0 end -- cannot tell how much time left, could be interrupted by a signal. 132 | return true 133 | end 134 | end 135 | 136 | -- common libc function 137 | if not S.sleep and S.nanosleep then 138 | function S.sleep(sec) 139 | local ok, err, rem = S.nanosleep(sec) 140 | if not ok then return nil, err end 141 | if rem then return tonumber(rem.tv_sec) end 142 | return 0 143 | end 144 | end 145 | 146 | return S 147 | 148 | end 149 | 150 | return {init = init} 151 | 152 | -------------------------------------------------------------------------------- /test/ctest-openbsd.lua: -------------------------------------------------------------------------------- 1 | -- generate C test file to check ABI 2 | 3 | package.path = "./?.lua;" 4 | 5 | local abi = require "syscall.abi" 6 | 7 | local S = require "syscall" 8 | 9 | local abi = S.abi 10 | local types = S.types 11 | local t, ctypes, s = types.t, types.ctypes, types.s 12 | local c = S.c 13 | 14 | local ffi = require "ffi" 15 | 16 | local reflect = require "include.ffi-reflect.reflect" 17 | 18 | -- internal only 19 | c.errornames = nil 20 | 21 | -- fixups 22 | c.STD = nil 23 | c.EXIT = nil 24 | 25 | -- TODO this should be in system headers surely? (F_ULOCK, F_LOCK etc) 26 | 27 | for k, v in pairs(c.IOCTL) do if type(v) == "table" then c.IOCTL[k] = v.number end end 28 | 29 | c.AF.DECnet = c.AF.DECNET 30 | c.AF.DECNET = nil 31 | 32 | c.R_OK = c.OK.R 33 | c.W_OK = c.OK.W 34 | c.F_OK = c.OK.F 35 | c.X_OK = c.OK.X 36 | c.OK = nil 37 | 38 | c.SIGACT = nil -- TODO cast correctly instead, giving warning 39 | c.CHFLAGS.NODUMP = nil -- alias 40 | c.CHFLAGS.IMMUTABLE = nil -- alias 41 | c.CHFLAGS.APPEND = nil -- alias 42 | c.CHFLAGS.OPAQUE = nil -- alias 43 | 44 | c.W.WCLONE = nil -- underscore in name, changed 45 | c.W.WALL = nil -- underscore in name, changed 46 | c.W.STOPPED = nil -- underscore in name, changed 47 | 48 | -- these are Linux names TODO are there actually BSD names? 49 | ctypes["struct ethhdr"] = nil 50 | ctypes["struct iphdr"] = nil 51 | ctypes["struct udphdr"] = nil 52 | 53 | -- not all syscalls always defined, some conditional, some very new 54 | 55 | print [[ 56 | /* this code is generated by ctest-openbsd.lua */ 57 | 58 | #define _BSD_SOURCE 59 | 60 | #include 61 | #include 62 | 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | 98 | int ret = 0; 99 | 100 | void sassert(int a, int b, char *n) { 101 | if (a != b) { 102 | printf("error with %s: %d (0x%x) != %d (0x%x)\n", n, a, a, b, b); 103 | ret = 1; 104 | } 105 | } 106 | 107 | void sassert_u64(unsigned long long a, unsigned long long b, char *n) { 108 | if (a != b) { 109 | printf("error with %s: %llu (0x%llx) != %llu (0x%llx)\n", n, (unsigned long long)a, (unsigned long long)a, (unsigned long long)b, (unsigned long long)b); 110 | ret = 1; 111 | } 112 | } 113 | 114 | int main(int argc, char **argv) { 115 | ]] 116 | 117 | local ignore_offsets = { 118 | sig = "true", -- sigset_t renamed TODO rename back 119 | } 120 | 121 | -- iterate over S.ctypes 122 | for k, v in pairs(ctypes) do 123 | print("sassert(sizeof(" .. k .. "), " .. ffi.sizeof(v) .. ', "' .. k .. '");') 124 | -- check offset of struct fields 125 | local refct = reflect.typeof(v) 126 | if refct.what == "struct" then 127 | for r in refct:members() do 128 | local name = r.name 129 | -- bit hacky - TODO fix these issues 130 | if ignore_offsets[name] then name = nil end 131 | if name then 132 | print("sassert(offsetof(" .. k .. "," .. name .. "), " .. ffi.offsetof(v, name) .. ', " offset of ' .. name .. ' in ' .. k .. '");') 133 | end 134 | end 135 | end 136 | end 137 | 138 | -- test all the constants 139 | 140 | -- renamed ones 141 | local nm = { 142 | E = "E", 143 | SIG = "SIG", 144 | STD = "STD", 145 | MODE = "S_I", 146 | MSYNC = "MS_", 147 | W = "W", 148 | POLL = "POLL", 149 | S_I = "S_I", 150 | LFLAG = "", 151 | IFLAG = "", 152 | OFLAG = "", 153 | CFLAG = "", 154 | CC = "", 155 | IOCTL = "", 156 | B = "B", 157 | AT_FDCWD = "AT_", 158 | FCNTL_LOCK = "F_", 159 | LOCKF = "F_", 160 | SIGACT = "SIG_", 161 | UMOUNT = "MNT_", 162 | SIGPM = "SIG_", 163 | OPIPE = "O_", 164 | MSYNC = "MS_", 165 | CHFLAGS = "", 166 | PC = "_PC_", 167 | FSYNC = "", 168 | TCSA = "TCSA", 169 | TCFLUSH = "TC", 170 | TCFLOW = "TC", 171 | VFSMNT = "MNT_", 172 | BRDG = "BRDG", 173 | } 174 | 175 | for k, v in pairs(c) do 176 | if type(v) == "number" then 177 | print("sassert(" .. k .. ", " .. v .. ', "' .. k .. '");') 178 | elseif type(v) == "table" then 179 | for k2, v2 in pairs(v) do 180 | local name = nm[k] or k .. "_" 181 | if type(v2) ~= "function" then 182 | if type(v2) == "cdata" and ffi.sizeof(v2) == 8 then 183 | print("sassert_u64(" .. name .. k2 .. ", " .. tostring(v2) .. ', "' .. name .. k2 .. '");') 184 | else 185 | print("sassert(" .. name .. k2 .. ", " .. tostring(tonumber(v2)) .. ', "' .. name .. k2 .. '");') 186 | end 187 | end 188 | end 189 | end 190 | end 191 | 192 | print [[ 193 | return ret; 194 | } 195 | ]] 196 | 197 | -------------------------------------------------------------------------------- /test/ctest-osx.lua: -------------------------------------------------------------------------------- 1 | -- generate C test file to check type sizes etc 2 | -- OSX version, similar to BSD 3 | 4 | local S = require "syscall" 5 | 6 | local abi = S.abi 7 | local types = S.types 8 | local t, ctypes, s = types.t, types.ctypes, types.s 9 | local c = S.c 10 | 11 | local ffi = require "ffi" 12 | 13 | local reflect = require "include.ffi-reflect.reflect" 14 | 15 | -- internal 16 | c.errornames = nil 17 | 18 | -- fixups 19 | c.AF.DECnet = c.AF.DECNET 20 | c.AF.DECNET = nil 21 | 22 | c.CHFLAGS.IMMUTABLE = nil -- alias 23 | c.CHFLAGS.APPEND = nil -- alias 24 | c.CHFLAGS.OPAQUE = nil -- alias 25 | 26 | c.CLOCKTYPE.SYSTEM_CLOCK, c.CLOCKTYPE.SYSTEM = c.CLOCKTYPE.SYSTEM, nil 27 | c.CLOCKTYPE.CALENDAR_CLOCK, c.CLOCKTYPE.CALENDAR = c.CLOCKTYPE.CALENDAR, nil 28 | c.CLOCKTYPE.REALTIME_CLOCK, c.CLOCKTYPE.REALTIME = c.CLOCKTYPE.REALTIME, nil 29 | 30 | c.R_OK = c.OK.R 31 | c.W_OK = c.OK.W 32 | c.F_OK = c.OK.F 33 | c.X_OK = c.OK.X 34 | c.OK = nil 35 | 36 | c.STD.IN = nil 37 | c.STD.OUT = nil 38 | c.STD.ERR = nil 39 | 40 | c.SIGACT = nil -- TODO cast correctly instead, giving warning 41 | 42 | for k, v in pairs(c.IOCTL) do if type(v) == "table" then c.IOCTL[k] = v.number end end 43 | 44 | -- these are Linux names TODO are there actually BSD names? 45 | ctypes["struct ethhdr"] = nil 46 | ctypes["struct iphdr"] = nil 47 | ctypes["struct udphdr"] = nil 48 | 49 | ctypes["struct legacy_dirent"] = nil 50 | 51 | -- doesnt actually exist in osx 52 | ctypes["clockid_t"] = nil 53 | ctypes["struct itimerspec"] = nil 54 | 55 | print [[ 56 | /* this code is generated by ctest-bsd.lua */ 57 | 58 | #define _FILE_OFFSET_BITS 64 59 | #define _LARGE_FILES 1 60 | #define __USE_FILE_OFFSET64 61 | #define _INCOMPLETE_XOPEN_C063 62 | 63 | #include 64 | #include 65 | 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | 105 | int ret = 0; 106 | 107 | void sassert(int a, int b, char *n) { 108 | if (a != b) { 109 | printf("error with %s: %d (0x%x) != %d (0x%x)\n", n, a, a, b, b); 110 | ret = 1; 111 | } 112 | } 113 | 114 | void sassert_u64(uint64_t a, uint64_t b, char *n) { 115 | if (a != b) { 116 | printf("error with %s: %llu (0x%llx) != %llu (0x%llx)\n", n, (unsigned long long)a, (unsigned long long)a, (unsigned long long)b, (unsigned long long)b); 117 | ret = 1; 118 | } 119 | } 120 | 121 | int main(int argc, char **argv) { 122 | ]] 123 | 124 | local ignore_offsets = { 125 | sig = "true", -- sigset_t renamed TODO rename back 126 | } 127 | 128 | -- iterate over S.ctypes 129 | for k, v in pairs(ctypes) do 130 | print("sassert(sizeof(" .. k .. "), " .. ffi.sizeof(v) .. ', "' .. k .. '");') 131 | -- check offset of struct fields 132 | local refct = reflect.typeof(v) 133 | if refct.what == "struct" then 134 | for r in refct:members() do 135 | local name = r.name 136 | -- bit hacky - TODO fix these issues 137 | if ignore_offsets[name] then name = nil end 138 | if name then 139 | print("sassert(offsetof(" .. k .. "," .. name .. "), " .. ffi.offsetof(v, name) .. ', " offset of ' .. name .. ' in' .. k .. '");') 140 | end 141 | end 142 | end 143 | end 144 | 145 | -- test all the constants 146 | 147 | -- renamed ones 148 | local nm = { 149 | E = "E", 150 | SIG = "SIG", 151 | STD = "STD", 152 | MODE = "S_I", 153 | MSYNC = "MS_", 154 | W = "W", 155 | POLL = "POLL", 156 | S_I = "S_I", 157 | LFLAG = "", 158 | IFLAG = "", 159 | OFLAG = "", 160 | CFLAG = "", 161 | CC = "", 162 | IOCTL = "", 163 | B = "B", 164 | SYS = "SYS___", 165 | AT_FDCWD = "AT_", 166 | FCNTL_LOCK = "F_", 167 | SIGACT = "SIG_", 168 | UMOUNT = "MNT_", 169 | SIGPM = "SIG_", 170 | FCNTL_LOCK = "F_", 171 | LOCKF = "F_", 172 | PC = "_PC_", 173 | TCSA = "TCSA", 174 | TCFLUSH = "TC", 175 | TCFLOW = "TC", 176 | CHFLAGS = "", 177 | CLOCKTYPE = "", 178 | } 179 | 180 | for k, v in pairs(c) do 181 | if type(v) == "number" then 182 | print("sassert(" .. k .. ", " .. v .. ', "' .. k .. '");') 183 | elseif type(v) == "table" then 184 | for k2, v2 in pairs(v) do 185 | local name = nm[k] or k .. "_" 186 | if type(v2) ~= "function" then 187 | if type(v2) == "cdata" and ffi.sizeof(v2) == 8 then 188 | print("sassert_u64(" .. name .. k2 .. ", " .. tostring(v2) .. ', "' .. name .. k2 .. '");') 189 | else 190 | print("sassert(" .. name .. k2 .. ", " .. tostring(tonumber(v2)) .. ', "' .. name .. k2 .. '");') 191 | end 192 | end 193 | end 194 | end 195 | end 196 | 197 | print [[ 198 | return ret; 199 | } 200 | ]] 201 | 202 | -------------------------------------------------------------------------------- /test/ctest-freebsd.lua: -------------------------------------------------------------------------------- 1 | -- generate C test file to check ABI 2 | 3 | package.path = "./?.lua;" 4 | 5 | local abi = require "syscall.abi" 6 | 7 | local version = require "syscall.freebsd.version".version 8 | 9 | local S = require "syscall" 10 | 11 | local abi = S.abi 12 | local types = S.types 13 | local t, ctypes, s = types.t, types.ctypes, types.s 14 | local c = S.c 15 | 16 | local ffi = require "ffi" 17 | 18 | local reflect = require "include.ffi-reflect.reflect" 19 | 20 | -- internal only 21 | c.errornames = nil 22 | 23 | -- fixups 24 | c.STD = nil 25 | c.EXIT = nil 26 | 27 | -- TODO this should be in system headers surely? (F_ULOCK, F_LOCK etc) 28 | c.LOCKF = nil 29 | 30 | for k, v in pairs(c.IOCTL) do if type(v) == "table" then c.IOCTL[k] = v.number end end 31 | 32 | c.AF.DECnet = c.AF.DECNET 33 | c.AF.DECNET = nil 34 | 35 | c.R_OK = c.OK.R 36 | c.W_OK = c.OK.W 37 | c.F_OK = c.OK.F 38 | c.X_OK = c.OK.X 39 | c.OK = nil 40 | 41 | c.SIGACT = nil -- TODO cast correctly instead, giving warning 42 | c.CHFLAGS.NODUMP = nil -- alias 43 | c.CHFLAGS.IMMUTABLE = nil -- alias 44 | c.CHFLAGS.APPEND = nil -- alias 45 | c.CHFLAGS.OPAQUE = nil -- alias 46 | c.CHFLAGS.NOUNLINK = nil -- alias 47 | 48 | c.W.WCLONE = nil -- underscore in name, changed 49 | c.W.WALL = nil -- underscore in name, changed 50 | 51 | c.SHM.ANON = tonumber(c.SHM.ANON) -- it is cast to a pointer 52 | 53 | -- these are Linux names TODO are there actually BSD names? 54 | ctypes["struct ethhdr"] = nil 55 | ctypes["struct iphdr"] = nil 56 | ctypes["struct udphdr"] = nil 57 | 58 | if version < 10 then 59 | ctypes.cap_rights_t = nil 60 | end 61 | 62 | print [[ 63 | /* this code is generated by ctest-freebsd.lua */ 64 | 65 | #include 66 | #include 67 | 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | ]] 106 | 107 | if version >= 10 then print [[ 108 | #include 109 | ]] 110 | end 111 | 112 | print [[ 113 | 114 | int ret = 0; 115 | 116 | void sassert(int a, int b, char *n) { 117 | if (a != b) { 118 | printf("error with %s: %d (0x%x) != %d (0x%x)\n", n, a, a, b, b); 119 | ret = 1; 120 | } 121 | } 122 | 123 | void sassert_u64(unsigned long long a, unsigned long long b, char *n) { 124 | if (a != b) { 125 | printf("error with %s: %llu (0x%llx) != %llu (0x%llx)\n", n, (unsigned long long)a, (unsigned long long)a, (unsigned long long)b, (unsigned long long)b); 126 | ret = 1; 127 | } 128 | } 129 | 130 | int main(int argc, char **argv) { 131 | ]] 132 | 133 | local ignore_offsets = { 134 | sig = "true", -- sigset_t renamed TODO rename back 135 | } 136 | 137 | -- iterate over S.ctypes 138 | for k, v in pairs(ctypes) do 139 | print("sassert(sizeof(" .. k .. "), " .. ffi.sizeof(v) .. ', "' .. k .. '");') 140 | -- check offset of struct fields 141 | local refct = reflect.typeof(v) 142 | if refct.what == "struct" then 143 | for r in refct:members() do 144 | local name = r.name 145 | -- bit hacky - TODO fix these issues 146 | if ignore_offsets[name] then name = nil end 147 | if name then 148 | print("sassert(offsetof(" .. k .. "," .. name .. "), " .. ffi.offsetof(v, name) .. ', " offset of ' .. name .. ' in ' .. k .. '");') 149 | end 150 | end 151 | end 152 | end 153 | 154 | -- test all the constants 155 | 156 | -- renamed ones 157 | local nm = { 158 | E = "E", 159 | SIG = "SIG", 160 | STD = "STD", 161 | MODE = "S_I", 162 | MSYNC = "MS_", 163 | W = "W", 164 | POLL = "POLL", 165 | S_I = "S_I", 166 | LFLAG = "", 167 | IFLAG = "", 168 | OFLAG = "", 169 | CFLAG = "", 170 | CC = "", 171 | IOCTL = "", 172 | B = "", 173 | AT_FDCWD = "AT_", 174 | FCNTL_LOCK = "F_", 175 | LOCKF = "F_", 176 | SIGACT = "SIG_", 177 | SIGPM = "SIG_", 178 | OPIPE = "O_", 179 | MSYNC = "MS_", 180 | CHFLAGS = "", 181 | PC = "_PC_", 182 | FSYNC = "", 183 | TCSA = "TCSA", 184 | TCFLUSH = "TC", 185 | TCFLOW = "TC", 186 | VFSMNT = "MNT_", 187 | BRDG = "BRDG", 188 | } 189 | 190 | for k, v in pairs(c) do 191 | if type(v) == "number" then 192 | print("sassert(" .. k .. ", " .. v .. ', "' .. k .. '");') 193 | elseif type(v) == "table" then 194 | for k2, v2 in pairs(v) do 195 | local name = nm[k] or k .. "_" 196 | if type(v2) ~= "function" then 197 | if type(v2) == "cdata" and ffi.sizeof(v2) == 8 then 198 | print("sassert_u64(" .. name .. k2 .. ", " .. tostring(v2) .. ', "' .. name .. k2 .. '");') 199 | else 200 | print("sassert(" .. name .. k2 .. ", " .. tostring(tonumber(v2)) .. ', "' .. name .. k2 .. '");') 201 | end 202 | end 203 | end 204 | end 205 | end 206 | 207 | print [[ 208 | return ret; 209 | } 210 | ]] 211 | 212 | --------------------------------------------------------------------------------