libc_service.slave

Synopsis

local libc_service = require "libc_service"

The handle to the slave end’s initialization data. When the handle is used in some function, it’s consumed and can no longer be used in different calls. The resources associated with the handle will be sent to the process created by the function that consumes this handle.

You cannot configure properties from this handle after a call that consumes it (e.g. spawn_vm()). If some setting is desired, it must be prepared before the call that consumes this object.

Metamethods

__newindex()

Assigns a Lua chunk (the source code as a string) to run on the slave end when the libc function (identified by the key) is attempted. The Lua function will be called with the proxified libc function as the first argument (before the arguments that were passed to the attempted libc function call). If no Lua function is assigned and the libc function is called, the proxified libc function will be called directly.

The Lua function has access to the same API that is available to init.script(3em). However errexit will be false by default.

libc_service_filters

Whether the proxified function forwards the request to the real libc depends on libc_service.master's reply. If the Lua chunk never calls the proxified function, then the proxified function never even runs.

Available Lua filters

This section lists the Lua filters you can implement to run when an interposed libc function is called.

open(real_open: function, path: string, flags: integer[, mode: integer]) → integer[, integer]

Returns:

  • The value for open()'s return.

  • Optional: The value for errno.

openat(real_openat: function, dirfd: integer, path: string, flags: integer, mode: integer, resolve: string[]) → integer[, integer]

mode will be 0 on unused.

resolve will be translated to whatever the current system uses under the hood (e.g. openat2() on Linux). Unsupported values won’t be silently ignored. If some flag is unsupported, the function will return with an error. It may contain:

"beneath"

Path resolution must not cross the fd directory.

"in_root"

Treat the directory referred to by dirfd as the root directory while resolving pathname. Absolute symbolic links are interpreted relative to dirfd.

"no_magiclinks"

Disallow all magic-link resolution during path resolution.

"no_symlinks"

Disallow resolution of symbolic links during path resolution.

"no_xdev"

Disallow traversal of mount points during path resolution (including all bind mounts).

"cached"

Make the open operation fail unless all path components are already present in the kernel’s lookup cache.

Returns:

  • The value for openat()'s return.

  • Optional: The value for errno.

Returns:

  • The value for unlink()'s return.

  • Optional: The value for errno.

rename(real_rename: function, path1: string, path2: string) → integer[, integer]

Returns:

  • The value for rename()'s return.

  • Optional: The value for errno.

stat(real_stat: function, path: string) → integer|table[, integer]

Returns:

  • The value for stat()'s return. Or Lua table on success (return 0).

  • Optional: The value for errno.

lstat(real_lstat: function, path: string) → integer|table[, integer]

Returns:

  • The value for lstat()'s return. Or Lua table on success (return 0).

  • Optional: The value for errno.

access(real_access: function, path: string, amode: integer) → integer[, integer]

Returns:

  • The value for access()'s return.

  • Optional: The value for errno.

eaccess(real_eaccess: function, path: string, amode: integer) → integer[, integer]

Returns:

  • The value for eaccess()'s return.

  • Optional: The value for errno.

mkdir(real_mkdir: function, path: string, mode: integer) → integer[, integer]

Returns:

  • The value for mkdir()'s return.

  • Optional: The value for errno.

rmdir(real_rmdir: function, path: string) → integer[, integer]

Returns:

  • The value for rmdir()'s return.

  • Optional: The value for errno.

connect_unix(real_connect: function, fd: integer, path: string) → integer[, integer]

Returns:

  • The value for connect()'s return.

  • Optional: The value for errno.

connect_inet(real_connect: function, fd: integer, ipv4_addr: integer[], port: integer) → integer[, integer]

Returns:

  • The value for connect()'s return.

  • Optional: The value for errno.

connect_inet6(real_connect: function, fd: integer, ipv6_addr: integer[], port: integer, scope_id: integer) → integer[, integer]

Returns:

  • The value for connect()'s return.

  • Optional: The value for errno.

bind_unix(real_bind: function, fd: integer, path: string) → integer[, integer]

Returns:

  • The value for bind()'s return.

  • Optional: The value for errno.

bind_inet(real_bind: function, fd: integer, ipv4_addr: integer[], port: integer) → integer[, integer]

Returns:

  • The value for bind()'s return.

  • Optional: The value for errno.

bind_inet6(real_bind: function, fd: integer, ipv6_addr: integer[], port: integer, scope_id: integer) → integer[, integer]

Returns:

  • The value for bind()'s return.

  • Optional: The value for errno.

getaddrinfo(real_getaddrinfo: function, node: string, service: string, protocol: "tcp"|"udp"|nil) → …​

To indicate failure, this function should return one of strings below or some equivalent integer code:

  • "again"

  • "badflags"

  • "fail"

  • "family"

  • "memory"

  • "noname"

  • "service"

  • "socktype"

  • "system"

If "system" is returned, another integer value for errno should follow.

To indicate success without any resolved address, the function should return just nil.

To indicate success with a resolved address, the function should return the following values:

nil

It’s here just to disambiguate against other cases.

ip_addr: integer[]

On IPv6 addresses, it should include an extra integer at the end for the scope ID.

port: integer

The port.