% GENERATED: DO NOT EDIT
%%% % @noformat
-module(alcove).
-include("alcove.hrl").
% Generated functions
-export([alloc/3,
cap_constant/3,
cap_enter/2,
cap_fcntls_get/3,
cap_fcntls_limit/4,
cap_getmode/2,
cap_ioctls_limit/4,
cap_rights_limit/4,
chdir/3,
chmod/4,
chown/5,
chroot/3,
clearenv/2,
clone/3,
clone_constant/3,
close/3,
connect/4,
cpid/2,
environ/2,
errno_id/3,
execve/5,
execvp/4,
exit/3,
fcntl/5,
fcntl_constant/3,
fexecve/5,
file_constant/3,
filter/4,
fork/2,
getcwd/2,
getenv/3,
getgid/2,
getgroups/2,
gethostname/2,
getopt/3,
getpgrp/2,
getpid/2,
getpriority/4,
getresgid/2,
getresuid/2,
getrlimit/3,
getsid/3,
getuid/2,
ioctl/5,
ioctl_constant/3,
iolist_to_bin/3,
jail/3,
jail_attach/3,
jail_remove/3,
kill/4,
link/4,
lseek/5,
mkdir/4,
mkfifo/4,
mount/8,
mount_constant/3,
open/5,
pivot_root/4,
pledge/4,
prctl/7,
prctl_constant/3,
procctl/6,
ptrace/6,
ptrace_constant/3,
read/4,
readdir/3,
rlimit_constant/3,
rmdir/3,
seccomp/5,
seccomp_constant/3,
select/6,
setcpid/5,
setenv/5,
setgid/3,
setgroups/3,
sethostname/3,
setns/4,
setopt/4,
setpgid/4,
setpriority/5,
setproctitle/3,
setresgid/5,
setresuid/5,
setrlimit/4,
setsid/2,
setuid/3,
sigaction/4,
signal_constant/3,
socket/5,
symlink/4,
syscall_constant/3,
umount/3,
umount2/4,
unlink/3,
unsetenv/3,
unshare/3,
unveil/4,
version/2,
waitpid/4,
write/4]).
-export([alloc/4,
cap_constant/4,
cap_enter/3,
cap_fcntls_get/4,
cap_fcntls_limit/5,
cap_getmode/3,
cap_ioctls_limit/5,
cap_rights_limit/5,
chdir/4,
chmod/5,
chown/6,
chroot/4,
clearenv/3,
clone/4,
clone_constant/4,
close/4,
connect/5,
cpid/3,
environ/3,
errno_id/4,
execve/6,
execvp/5,
exit/4,
fcntl/6,
fcntl_constant/4,
fexecve/6,
file_constant/4,
filter/5,
fork/3,
getcwd/3,
getenv/4,
getgid/3,
getgroups/3,
gethostname/3,
getopt/4,
getpgrp/3,
getpid/3,
getpriority/5,
getresgid/3,
getresuid/3,
getrlimit/4,
getsid/4,
getuid/3,
ioctl/6,
ioctl_constant/4,
iolist_to_bin/4,
jail/4,
jail_attach/4,
jail_remove/4,
kill/5,
link/5,
lseek/6,
mkdir/5,
mkfifo/5,
mount/9,
mount_constant/4,
open/6,
pivot_root/5,
pledge/5,
prctl/8,
prctl_constant/4,
procctl/7,
ptrace/7,
ptrace_constant/4,
read/5,
readdir/4,
rlimit_constant/4,
rmdir/4,
seccomp/6,
seccomp_constant/4,
select/7,
setcpid/6,
setenv/6,
setgid/4,
setgroups/4,
sethostname/4,
setns/5,
setopt/5,
setpgid/5,
setpriority/6,
setproctitle/4,
setresgid/6,
setresuid/6,
setrlimit/5,
setsid/3,
setuid/4,
sigaction/5,
signal_constant/4,
socket/6,
symlink/5,
syscall_constant/4,
umount/4,
umount2/5,
unlink/4,
unsetenv/4,
unshare/4,
unveil/5,
version/3,
waitpid/5,
write/5]).
-type uint8_t() :: 0..16#ff.
-type uint16_t() :: 0..16#ffff.
-type uint32_t() :: 0..16#ffffffff.
-type uint64_t() :: 0..16#ffffffffffffffff.
-type int8_t() :: -16#7f..16#7f.
-type int16_t() :: -16#7fff..16#7fff.
-type int32_t() :: -16#7fffffff..16#7fffffff.
-type int64_t() :: -16#7fffffffffffffff..16#7fffffffffffffff.
-type mode_t() :: uint32_t().
-type uid_t() :: uint32_t().
-type gid_t() :: uint32_t().
-type off_t() :: uint64_t().
-type size_t() :: uint64_t().
-type ssize_t() :: int64_t().
-type pid_t() :: int32_t().
-type fd() :: int32_t().
-type fd_set() :: [fd()].
-type constant() :: atom() | integer().
-type cstruct() :: nonempty_list(binary() | {ptr, binary() | non_neg_integer()}).
-type posix() ::
e2big
| eacces
| eaddrinuse
| eaddrnotavail
| eadv
| eafnosupport
| eagain
| ealign
| ealready
| ebade
| ebadf
| ebadfd
| ebadmsg
| ebadr
| ebadrpc
| ebadrqc
| ebadslt
| ebfont
| ebusy
| ecapmode
| echild
| echrng
| ecomm
| econnaborted
| econnrefused
| econnreset
| edeadlk
| edeadlock
| edestaddrreq
| edirty
| edom
| edotdot
| edquot
| eduppkg
| eexist
| efault
| efbig
| ehostdown
| ehostunreach
| eidrm
| einit
| einprogress
| eintr
| einval
| eio
| eisconn
| eisdir
| eisnam
| el2hlt
| el2nsync
| el3hlt
| el3rst
| elbin
| elibacc
| elibbad
| elibexec
| elibmax
| elibscn
| elnrng
| eloop
| emfile
| emlink
| emsgsize
| emultihop
| enametoolong
| enavail
| enet
| enetdown
| enetreset
| enetunreach
| enfile
| enoano
| enobufs
| enocsi
| enodata
| enodev
| enoent
| enoexec
| enolck
| enolink
| enomem
| enomsg
| enonet
| enopkg
| enoprotoopt
| enospc
| enosr
| enostr
| enosym
| enosys
| enotblk
| enotcapable
| enotconn
| enotdir
| enotempty
| enotnam
| enotrecoverable
| enotsock
| enotsup
| enotty
| enotuniq
| enxio
| eopnotsupp
| eoverflow
| eownerdead
| eperm
| epfnosupport
| epipe
| eproclim
| eprocunavail
| eprogmismatch
| eprogunavail
| eproto
| eprotonosupport
| eprototype
| erange
| erefused
| eremchg
| eremdev
| eremote
| eremoteio
| eremoterelease
| erofs
| erpcmismatch
| erremote
| eshutdown
| esocktnosupport
| espipe
| esrch
| esrmnt
| estale
| esuccess
| etime
| etimedout
| etoomanyrefs
| etxtbsy
| euclean
| eunatch
| eusers
| eversion
| ewouldblock
| exdev
| exfull.
-type alcove_pid_field() ::
pid
| flowcontrol
| signaloneof
| fdctl
| stdin
| stdout
| stderr.
-type alcove_pid() :: #alcove_pid{}.
-type alcove_rlimit() :: #alcove_rlimit{}.
-type alcove_timeval() :: #alcove_timeval{}.
-type filter() ::
alcove_proto:calls()
| []
| {deny, alcove_proto:calls() | []}
| {allow, alcove_proto:calls() | []}.
-export_type([
uint8_t/0,
uint16_t/0,
uint32_t/0,
uint64_t/0,
int8_t/0,
int16_t/0,
int32_t/0,
int64_t/0,
mode_t/0,
uid_t/0,
gid_t/0,
off_t/0,
size_t/0,
ssize_t/0,
fd/0,
fd_set/0,
pid_t/0,
constant/0,
posix/0,
filter/0,
alcove_pid_field/0,
alcove_pid/0,
alcove_rlimit/0,
alcove_timeval/0
]).
-spec alloc(alcove_drv:ref(), [pid_t()], Ptr :: cstruct()) -> {ok, binary(), iodata()}.
-spec alloc(alcove_drv:ref(), [pid_t()], Ptr :: cstruct(), timeout()) ->
{ok, binary(), iodata()}.
-spec cap_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) -> integer() | unknown.
-spec cap_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
integer() | unknown.
-spec cap_enter(alcove_drv:ref(), [pid_t()]) -> ok | {error, posix()}.
-spec cap_enter(alcove_drv:ref(), [pid_t()], timeout()) -> ok | {error, posix()}.
-spec cap_fcntls_get(alcove_drv:ref(), [pid_t()], FD :: fd()) ->
{ok, integer()} | {error, posix()}.
-spec cap_fcntls_get(alcove_drv:ref(), [pid_t()], FD :: fd(), timeout()) ->
{ok, integer()} | {error, posix()}.
-spec cap_fcntls_limit(alcove_drv:ref(), [pid_t()], FD :: fd(), Rights :: constant()) ->
ok | {error, posix()}.
-spec cap_fcntls_limit(alcove_drv:ref(), [pid_t()], FD :: fd(), Rights :: constant(), timeout()) ->
ok | {error, posix()}.
-spec cap_getmode(alcove_drv:ref(), [pid_t()]) -> {ok, 0 | 1} | {error, posix()}.
-spec cap_getmode(alcove_drv:ref(), [pid_t()], timeout()) -> {ok, 0 | 1} | {error, posix()}.
-spec cap_ioctls_limit(alcove_drv:ref(), [pid_t()], FD :: fd(), Rights :: constant()) ->
ok | {error, posix()}.
-spec cap_ioctls_limit(alcove_drv:ref(), [pid_t()], FD :: fd(), Rights :: constant(), timeout()) ->
ok | {error, posix()}.
-spec cap_rights_limit(alcove_drv:ref(), [pid_t()], FD :: fd(), Rights :: constant()) ->
ok | {error, posix()}.
-spec cap_rights_limit(alcove_drv:ref(), [pid_t()], FD :: fd(), Rights :: constant(), timeout()) ->
ok | {error, posix()}.
-spec chdir(alcove_drv:ref(), [pid_t()], Path :: iodata()) -> ok | {error, posix()}.
-spec chdir(alcove_drv:ref(), [pid_t()], Path :: iodata(), timeout()) -> ok | {error, posix()}.
-spec cpid(alcove_drv:ref(), [pid_t()]) -> [alcove_pid()].
-spec cpid(alcove_drv:ref(), [pid_t()], timeout()) -> [alcove_pid()].
-spec chmod(alcove_drv:ref(), [pid_t()], Path :: iodata(), Mode :: mode_t()) ->
ok | {error, posix()}.
-spec chmod(alcove_drv:ref(), [pid_t()], Path :: iodata(), Mode :: mode_t(), timeout()) ->
ok | {error, posix()}.
-spec chown(alcove_drv:ref(), [pid_t()], Path :: iodata(), Owner :: uid_t(), Group :: gid_t()) ->
ok | {error, posix()}.
-spec chown(
alcove_drv:ref(), [pid_t()], Path :: iodata(), Owner :: uid_t(), Group :: gid_t(), timeout()
) ->
ok | {error, posix()}.
-spec chroot(alcove_drv:ref(), [pid_t()], Path :: iodata()) -> ok | {error, posix()}.
-spec chroot(alcove_drv:ref(), [pid_t()], Path :: iodata(), timeout()) -> ok | {error, posix()}.
-spec clearenv(alcove_drv:ref(), [pid_t()]) -> ok | {error, posix()}.
-spec clearenv(alcove_drv:ref(), [pid_t()], timeout()) -> ok | {error, posix()}.
-spec clone(alcove_drv:ref(), [pid_t()], Flags :: int32_t() | [constant()]) ->
{ok, pid_t()} | {error, posix()}.
-spec clone(alcove_drv:ref(), [pid_t()], Flags :: int32_t() | [constant()], timeout()) ->
{ok, pid_t()} | {error, posix()}.
-spec clone_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) -> unknown | int32_t().
-spec clone_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | int32_t().
-spec close(alcove_drv:ref(), [pid_t()], FD :: fd()) -> ok | {error, posix()}.
-spec close(alcove_drv:ref(), [pid_t()], FD :: fd(), timeout()) -> ok | {error, posix()}.
-spec connect(alcove_drv:ref(), [pid_t()], FD :: fd(), Sockaddr :: [] | cstruct()) ->
ok | {error, posix()}.
-spec connect(alcove_drv:ref(), [pid_t()], FD :: fd(), Sockaddr :: [] | cstruct(), timeout()) ->
ok | {error, posix()}.
-spec environ(alcove_drv:ref(), [pid_t()]) -> [binary()].
-spec environ(alcove_drv:ref(), [pid_t()], timeout()) -> [binary()].
-spec errno_id(alcove_drv:ref(), [pid_t()], Errno :: int32_t()) -> posix().
-spec errno_id(alcove_drv:ref(), [pid_t()], Errno :: int32_t(), timeout()) -> posix().
-spec execve(alcove_drv:ref(), [pid_t()], Arg0 :: iodata(), Argv :: [iodata()], Env :: [iodata()]) ->
ok | {error, posix()}.
-spec execve(
alcove_drv:ref(), [pid_t()], Arg0 :: iodata(), Argv :: [iodata()], Env :: [iodata()], timeout()
) ->
ok | {error, posix()}.
-spec execvp(alcove_drv:ref(), [pid_t()], Arg0 :: iodata(), Argv :: [iodata()]) ->
ok | {error, posix()}.
-spec execvp(alcove_drv:ref(), [pid_t()], Arg0 :: iodata(), Argv :: [iodata()], timeout()) ->
ok | {error, posix()}.
-spec exit(alcove_drv:ref(), [pid_t()], Status :: int32_t()) -> ok.
-spec exit(alcove_drv:ref(), [pid_t()], Status :: int32_t(), timeout()) -> ok.
-spec fcntl(alcove_drv:ref(), [pid_t()], FD :: fd(), Cmd :: constant(), Arg :: int64_t()) ->
{ok, int64_t()} | {error, posix()}.
-spec fcntl(
alcove_drv:ref(), [pid_t()], FD :: fd(), Cmd :: constant(), Arg :: int64_t(), timeout()
) ->
{ok, int64_t()} | {error, posix()}.
-spec fcntl_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) -> integer() | unknown.
-spec fcntl_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
integer() | unknown.
-spec fexecve(alcove_drv:ref(), [pid_t()], FD :: fd(), Argv :: [iodata()], Env :: [iodata()]) ->
ok | {error, posix()}.
-spec fexecve(
alcove_drv:ref(), [pid_t()], FD :: fd(), Argv :: [iodata()], Env :: [iodata()], timeout()
) ->
ok | {error, posix()}.
-spec file_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) -> non_neg_integer() | unknown.
-spec file_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
non_neg_integer() | unknown.
-spec filter(alcove_drv:ref(), [pid_t()], Calls :: binary(), Calls :: binary()) ->
ok | {error, einval}.
-spec filter(alcove_drv:ref(), [pid_t()], Calls :: binary(), Calls :: binary(), timeout()) ->
ok | {error, einval}.
-spec fork(alcove_drv:ref(), [pid_t()]) -> {ok, pid_t()} | {error, posix()}.
-spec fork(alcove_drv:ref(), [pid_t()], timeout()) -> {ok, pid_t()} | {error, posix()}.
-spec getcwd(alcove_drv:ref(), [pid_t()]) -> {ok, binary()} | {error, posix()}.
-spec getcwd(alcove_drv:ref(), [pid_t()], timeout()) -> {ok, binary()} | {error, posix()}.
-spec getenv(alcove_drv:ref(), [pid_t()], Name :: iodata()) -> binary() | false.
-spec getenv(alcove_drv:ref(), [pid_t()], Name :: iodata(), timeout()) -> binary() | false.
-spec getgid(alcove_drv:ref(), [pid_t()]) -> gid_t().
-spec getgid(alcove_drv:ref(), [pid_t()], timeout()) -> gid_t().
-spec getgroups(alcove_drv:ref(), [pid_t()]) -> {ok, [gid_t()]} | {error, posix()}.
-spec getgroups(alcove_drv:ref(), [pid_t()], timeout()) -> {ok, [gid_t()]} | {error, posix()}.
-spec gethostname(alcove_drv:ref(), [pid_t()]) -> {ok, binary()} | {error, posix()}.
-spec gethostname(alcove_drv:ref(), [pid_t()], timeout()) -> {ok, binary()} | {error, posix()}.
-spec getopt(alcove_drv:ref(), [pid_t()], Opt :: atom()) -> false | int32_t().
-spec getopt(alcove_drv:ref(), [pid_t()], Opt :: atom(), timeout()) -> false | int32_t().
-spec getpgrp(alcove_drv:ref(), [pid_t()]) -> pid_t().
-spec getpgrp(alcove_drv:ref(), [pid_t()], timeout()) -> pid_t().
-spec getpid(alcove_drv:ref(), [pid_t()]) -> pid_t().
-spec getpid(alcove_drv:ref(), [pid_t()], timeout()) -> pid_t().
-spec getpriority(alcove_drv:ref(), [pid_t()], Which :: constant(), Who :: int32_t()) ->
{ok, int32_t()} | {error, posix()}.
-spec getpriority(alcove_drv:ref(), [pid_t()], Which :: constant(), Who :: int32_t(), timeout()) ->
{ok, int32_t()} | {error, posix()}.
-spec getresgid(alcove_drv:ref(), [pid_t()]) ->
{ok, Real :: gid_t(), Effective :: gid_t(), Saved :: gid_t()} | {error, posix()}.
-spec getresgid(alcove_drv:ref(), [pid_t()], timeout()) ->
{ok, Real :: gid_t(), Effective :: gid_t(), Saved :: gid_t()} | {error, posix()}.
-spec getresuid(alcove_drv:ref(), [pid_t()]) ->
{ok, Real :: uid_t(), Effective :: uid_t(), Saved :: uid_t()} | {error, posix()}.
-spec getresuid(alcove_drv:ref(), [pid_t()], timeout()) ->
{ok, Real :: uid_t(), Effective :: uid_t(), Saved :: uid_t()} | {error, posix()}.
-spec getrlimit(alcove_drv:ref(), [pid_t()], Resource :: constant()) ->
{ok, alcove_rlimit()} | {error, posix()}.
-spec getrlimit(alcove_drv:ref(), [pid_t()], Resource :: constant(), timeout()) ->
{ok, alcove_rlimit()} | {error, posix()}.
-spec getsid(alcove_drv:ref(), [pid_t()], OSPid :: pid_t()) -> {ok, pid_t()} | {error, posix()}.
-spec getsid(alcove_drv:ref(), [pid_t()], OSPid :: pid_t(), timeout()) ->
{ok, pid_t()} | {error, posix()}.
-spec getuid(alcove_drv:ref(), [pid_t()]) -> uid_t().
-spec getuid(alcove_drv:ref(), [pid_t()], timeout()) -> uid_t().
-spec ioctl(alcove_drv:ref(), [pid_t()], FD :: fd(), Request :: constant(), Argp :: cstruct()) ->
{ok, integer(), iodata()} | {error, posix()}.
-spec ioctl(
alcove_drv:ref(), [pid_t()], FD :: fd(), Request :: constant(), Argp :: cstruct(), timeout()
) ->
{ok, integer(), iodata()} | {error, posix()}.
-spec ioctl_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) -> integer() | unknown.
-spec ioctl_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
integer() | unknown.
-spec iolist_to_bin(alcove_drv:ref(), [pid_t()], iodata()) -> binary().
-spec iolist_to_bin(alcove_drv:ref(), [pid_t()], iodata(), timeout()) -> binary().
-spec jail(alcove_drv:ref(), [pid_t()], Jail :: cstruct()) -> {ok, int32_t()} | {error, posix()}.
-spec jail(alcove_drv:ref(), [pid_t()], Jail :: cstruct(), timeout()) ->
{ok, int32_t()} | {error, posix()}.
-spec jail_attach(alcove_drv:ref(), [pid_t()], JID :: int32_t()) -> ok | {error, posix()}.
-spec jail_attach(alcove_drv:ref(), [pid_t()], JID :: int32_t(), timeout()) -> ok | {error, posix()}.
-spec jail_remove(alcove_drv:ref(), [pid_t()], JID :: int32_t()) -> ok | {error, posix()}.
-spec jail_remove(alcove_drv:ref(), [pid_t()], JID :: int32_t(), timeout()) -> ok | {error, posix()}.
-spec kill(alcove_drv:ref(), [pid_t()], OSPid :: pid_t(), Signal :: constant()) ->
ok | {error, posix()}.
-spec kill(alcove_drv:ref(), [pid_t()], OSPID :: pid_t(), Signal :: constant(), timeout()) ->
ok | {error, posix()}.
-spec link(alcove_drv:ref(), [pid_t()], OldPath :: iodata(), NewPath :: iodata()) ->
ok | {error, posix()}.
-spec link(alcove_drv:ref(), [pid_t()], OldPath :: iodata(), NewPath :: iodata(), timeout()) ->
ok | {error, posix()}.
-spec lseek(alcove_drv:ref(), [pid_t()], FD :: fd(), Offset :: off_t(), Whence :: int32_t()) ->
ok | {error, posix()}.
-spec lseek(
alcove_drv:ref(), [pid_t()], FD :: fd(), Offset :: off_t(), Whence :: int32_t(), timeout()
) ->
ok | {error, posix()}.
-spec mkdir(alcove_drv:ref(), [pid_t()], Path :: iodata(), Mode :: mode_t()) ->
ok | {error, posix()}.
-spec mkdir(alcove_drv:ref(), [pid_t()], Path :: iodata(), Mode :: mode_t(), timeout()) ->
ok | {error, posix()}.
-spec mkfifo(alcove_drv:ref(), [pid_t()], Path :: iodata(), Mode :: mode_t()) ->
ok | {error, posix()}.
-spec mkfifo(alcove_drv:ref(), [pid_t()], Path :: iodata(), Mode :: mode_t(), timeout()) ->
ok | {error, posix()}.
-spec mount(
alcove_drv:ref(),
[pid_t()],
Source :: iodata(),
Target :: iodata(),
FSType :: iodata(),
Flags :: uint64_t() | [constant()],
Data :: iodata(),
Options :: iodata()
) -> ok | {error, posix()}.
-spec mount(
alcove_drv:ref(),
[pid_t()],
Source :: iodata(),
Target :: iodata(),
FSType :: iodata(),
Flags :: uint64_t() | [constant()],
Data :: iodata(),
Options :: iodata(),
timeout()
) -> ok | {error, posix()}.
-spec mount_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) -> unknown | uint64_t().
-spec mount_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | uint64_t().
-spec open(
alcove_drv:ref(),
[pid_t()],
Path :: iodata(),
Flags :: int32_t() | [constant()],
Mode :: mode_t()
) ->
{ok, fd()} | {error, posix()}.
-spec open(
alcove_drv:ref(),
[pid_t()],
Path :: iodata(),
Flags :: int32_t() | [constant()],
Mode :: mode_t(),
timeout()
) ->
{ok, fd()} | {error, posix()}.
-spec pledge(alcove_drv:ref(), [pid_t()], Promises :: iodata(), ExecPromises :: iodata()) ->
ok | {error, posix()}.
-spec pledge(
alcove_drv:ref(), [pid_t()], Promises :: iodata(), ExecPromises :: iodata(), timeout()
) ->
ok | {error, posix()}.
-spec pivot_root(alcove_drv:ref(), [pid_t()], NewRoot :: iodata(), PutOld :: iodata()) ->
ok | {error, posix()}.
-spec pivot_root(alcove_drv:ref(), [pid_t()], NewRoot :: iodata(), PutOld :: iodata(), timeout()) ->
ok | {error, posix()}.
-type ptr_arg() :: binary() | constant() | cstruct().
-type ptr_val() :: binary() | integer() | cstruct().
-spec prctl(alcove_drv:ref(), [pid_t()], constant(), ptr_arg(), ptr_arg(), ptr_arg(), ptr_arg()) ->
{ok, integer(), ptr_val(), ptr_val(), ptr_val(), ptr_val()} | {error, posix()}.
-spec prctl(
alcove_drv:ref(), [pid_t()], constant(), ptr_arg(), ptr_arg(), ptr_arg(), ptr_arg(), timeout()
) ->
{ok, integer(), ptr_val(), ptr_val(), ptr_val(), ptr_val()} | {error, posix()}.
-spec prctl_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) ->
unknown | non_neg_integer().
-spec prctl_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | non_neg_integer().
-spec procctl(
alcove_drv:ref(),
[pid_t()],
IDType :: constant(),
ID :: pid_t(),
Cmd :: constant(),
Data :: [] | cstruct()
) ->
{ok, binary(), cstruct()} | {error, posix()}.
-spec procctl(
alcove_drv:ref(),
[pid_t()],
IDType :: constant(),
ID :: pid_t(),
Cmd :: constant(),
Data :: [] | cstruct(),
timeout()
) ->
{ok, binary(), cstruct()} | {error, posix()}.
-spec ptrace(
alcove_drv:ref(),
[pid_t()],
Request :: constant(),
OSPid :: pid_t(),
Addr :: ptr_arg(),
Data :: ptr_arg()
) ->
{ok, integer(), ptr_val(), ptr_val()} | {error, posix()}.
-spec ptrace(
alcove_drv:ref(),
[pid_t()],
Request :: constant(),
OSPid :: pid_t(),
Addr :: ptr_arg(),
Data :: ptr_arg(),
timeout()
) ->
{ok, integer(), ptr_val(), ptr_val()} | {error, posix()}.
-spec ptrace_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) ->
unknown | integer().
-spec ptrace_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | integer().
-spec read(alcove_drv:ref(), [pid_t()], FD :: fd(), Count :: size_t()) ->
{ok, binary()} | {error, posix()}.
-spec read(alcove_drv:ref(), [pid_t()], FD :: fd(), Count :: size_t(), timeout()) ->
{ok, binary()} | {error, posix()}.
-spec readdir(alcove_drv:ref(), [pid_t()], Path :: iodata()) ->
{ok, [binary()]} | {error, posix()}.
-spec readdir(alcove_drv:ref(), [pid_t()], Path :: iodata(), timeout()) ->
{ok, [binary()]} | {error, posix()}.
-spec rlimit_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) ->
unknown | non_neg_integer().
-spec rlimit_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | non_neg_integer().
-spec rmdir(alcove_drv:ref(), [pid_t()], Path :: iodata()) -> ok | {error, posix()}.
-spec rmdir(alcove_drv:ref(), [pid_t()], Path :: iodata(), timeout()) -> ok | {error, posix()}.
-spec seccomp(
alcove_drv:ref(), [pid_t()], Operation :: constant(), Flags :: constant(), Prog :: cstruct()
) ->
ok | {error, posix()}.
-spec seccomp(
alcove_drv:ref(),
[pid_t()],
Operation :: constant(),
Flags :: constant(),
Prog :: cstruct(),
timeout()
) ->
ok | {error, posix()}.
-spec seccomp_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) ->
unknown | non_neg_integer().
-spec seccomp_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | non_neg_integer().
-spec select(
alcove_drv:ref(),
[pid_t()],
Readfds :: fd_set(),
Writefds :: fd_set(),
Exceptfds :: fd_set(),
Timeval :: [] | alcove_timeval()
) -> {ok, Readset :: fd_set(), Writeset :: fd_set(), Exceptset :: fd_set()} | {error, posix()}.
-spec select(
alcove_drv:ref(),
[pid_t()],
Readfds :: fd_set(),
Writefds :: fd_set(),
Exceptfds :: fd_set(),
Timeval :: [] | alcove_timeval(),
timeout()
) -> {ok, Readset :: fd_set(), Writeset :: fd_set(), Exceptset :: fd_set()} | {error, posix()}.
-spec setcpid(
alcove_drv:ref(), [pid_t()], Child :: pid_t(), Opt :: alcove_pid_field(), Val :: int32_t()
) -> boolean().
-spec setcpid(
alcove_drv:ref(),
[pid_t()],
Child :: pid_t(),
Opt :: alcove_pid_field(),
Val :: int32_t(),
timeout()
) ->
boolean().
-spec setenv(
alcove_drv:ref(), [pid_t()], Name :: iodata(), Value :: iodata(), Overwrite :: int32_t()
) ->
ok | {error, posix()}.
-spec setenv(
alcove_drv:ref(),
[pid_t()],
Name :: iodata(),
Value :: iodata(),
Overwrite :: int32_t(),
timeout()
) ->
ok | {error, posix()}.
-spec setgid(alcove_drv:ref(), [pid_t()], Gid :: gid_t()) -> ok | {error, posix()}.
-spec setgid(alcove_drv:ref(), [pid_t()], Gid :: gid_t(), timeout()) -> ok | {error, posix()}.
-spec setgroups(alcove_drv:ref(), [pid_t()], Groups :: [gid_t()]) -> ok | {error, posix()}.
-spec setgroups(alcove_drv:ref(), [pid_t()], Groups :: [gid_t()], timeout()) ->
ok | {error, posix()}.
-spec sethostname(alcove_drv:ref(), [pid_t()], Hostname :: iodata()) -> ok | {error, posix()}.
-spec sethostname(alcove_drv:ref(), [pid_t()], Hostname :: iodata(), timeout()) ->
ok | {error, posix()}.
-spec setns(alcove_drv:ref(), [pid_t()], FD :: fd(), NSType :: constant()) ->
ok | {error, posix()}.
-spec setns(alcove_drv:ref(), [pid_t()], FD :: fd(), NSType :: constant(), timeout()) ->
ok | {error, posix()}.
-spec setopt(alcove_drv:ref(), [pid_t()], Opt :: atom(), Val :: int32_t()) -> boolean().
-spec setopt(alcove_drv:ref(), [pid_t()], Opt :: atom(), Val :: int32_t(), timeout()) -> boolean().
-spec setpgid(alcove_drv:ref(), [pid_t()], OSPid :: pid_t(), Pgid :: pid_t()) ->
ok | {error, posix()}.
-spec setpgid(alcove_drv:ref(), [pid_t()], OSPid :: pid_t(), Pgid :: pid_t(), timeout()) ->
ok | {error, posix()}.
-spec setpriority(
alcove_drv:ref(), [pid_t()], Which :: constant(), Who :: int32_t(), Prio :: int32_t()
) ->
ok | {error, posix()}.
-spec setpriority(
alcove_drv:ref(), [pid_t()], Which :: constant(), Who :: int32_t(), Prio :: int32_t(), timeout()
) ->
ok | {error, posix()}.
-spec setproctitle(alcove_drv:ref(), [pid_t()], Title :: iodata()) -> ok.
-spec setproctitle(alcove_drv:ref(), [pid_t()], Title :: iodata(), timeout()) -> ok.
-spec setresgid(
alcove_drv:ref(), [pid_t()], Real :: gid_t(), Effective :: gid_t(), Saved :: gid_t()
) ->
ok | {error, posix()}.
-spec setresgid(
alcove_drv:ref(), [pid_t()], Real :: gid_t(), Effective :: gid_t(), Saved :: gid_t(), timeout()
) ->
ok | {error, posix()}.
-spec setresuid(
alcove_drv:ref(), [pid_t()], Real :: uid_t(), Effective :: uid_t(), Saved :: uid_t()
) ->
ok | {error, posix()}.
-spec setresuid(
alcove_drv:ref(), [pid_t()], Real :: uid_t(), Effective :: uid_t(), Saved :: uid_t(), timeout()
) ->
ok | {error, posix()}.
-spec setrlimit(alcove_drv:ref(), [pid_t()], Resource :: constant(), Limit :: alcove_rlimit()) ->
ok | {error, posix()}.
-spec setrlimit(
alcove_drv:ref(), [pid_t()], Resource :: constant(), Limit :: alcove_rlimit(), timeout()
) ->
ok | {error, posix()}.
-spec setsid(alcove_drv:ref(), [pid_t()]) -> {ok, OSPid :: pid_t()} | {error, posix()}.
-spec setsid(alcove_drv:ref(), [pid_t()], timeout()) -> {ok, OSPid :: pid_t()} | {error, posix()}.
-spec setuid(alcove_drv:ref(), [pid_t()], User :: uid_t()) -> ok | {error, posix()}.
-spec setuid(alcove_drv:ref(), [pid_t()], User :: uid_t(), timeout()) -> ok | {error, posix()}.
-spec sigaction(alcove_drv:ref(), [pid_t()], Signum :: constant(), Handler :: [] | atom()) ->
{ok, OldHandler :: atom()} | {error, posix()}.
-spec sigaction(
alcove_drv:ref(), [pid_t()], Signum :: constant(), Handler :: [] | atom(), timeout()
) ->
{ok, OldHandler :: atom()} | {error, posix()}.
-spec signal_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) ->
unknown | non_neg_integer().
-spec signal_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | non_neg_integer().
-spec socket(
alcove_drv:ref(), [pid_t()], Domain :: constant(), Type :: constant(), Protocol :: int32_t()
) ->
{ok, fd()} | {error, posix()}.
-spec socket(
alcove_drv:ref(),
[pid_t()],
Domain :: constant(),
Type :: constant(),
Protocol :: int32_t(),
timeout()
) ->
{ok, fd()} | {error, posix()}.
-spec syscall_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom()) ->
unknown | non_neg_integer().
-spec syscall_constant(alcove_drv:ref(), [pid_t()], Symbol :: atom(), timeout()) ->
unknown | non_neg_integer().
-spec symlink(alcove_drv:ref(), [pid_t()], OldPath :: iodata(), NewPath :: iodata()) ->
ok | {error, posix()}.
-spec symlink(alcove_drv:ref(), [pid_t()], OldPath :: iodata(), NewPath :: iodata(), timeout()) ->
ok | {error, posix()}.
-spec unlink(alcove_drv:ref(), [pid_t()], Path :: iodata()) -> ok | {error, posix()}.
-spec unlink(alcove_drv:ref(), [pid_t()], Path :: iodata(), timeout()) -> ok | {error, posix()}.
-spec umount(alcove_drv:ref(), [pid_t()], Path :: iodata()) -> ok | {error, posix()}.
-spec umount(alcove_drv:ref(), [pid_t()], Path :: iodata(), timeout()) -> ok | {error, posix()}.
-spec umount2(alcove_drv:ref(), [pid_t()], Path :: iodata(), Flags :: int32_t() | [constant()]) ->
ok | {error, posix()}.
-spec umount2(
alcove_drv:ref(), [pid_t()], Path :: iodata(), Flags :: int32_t() | [constant()], timeout()
) ->
ok | {error, posix()}.
-spec unsetenv(alcove_drv:ref(), [pid_t()], Name :: iodata()) -> ok | {error, posix()}.
-spec unsetenv(alcove_drv:ref(), [pid_t()], Name :: iodata(), timeout()) -> ok | {error, posix()}.
-spec unshare(alcove_drv:ref(), [pid_t()], Flags :: int32_t() | [constant()]) ->
ok | {error, posix()}.
-spec unshare(alcove_drv:ref(), [pid_t()], Flags :: int32_t() | [constant()], timeout()) ->
ok | {error, posix()}.
-spec unveil(alcove_drv:ref(), [pid_t()], Path :: iodata(), Permissions :: iodata()) ->
ok | {error, posix()}.
-spec unveil(alcove_drv:ref(), [pid_t()], Path :: iodata(), Permissions :: iodata(), timeout()) ->
ok | {error, posix()}.
-type waitstatus() ::
{exit_status, int32_t()}
| {termsig, atom()}
| {stopsig, atom()}
| continued.
-spec waitpid(alcove_drv:ref(), [pid_t()], OSPid :: pid_t(), Options :: int32_t() | [constant()]) ->
{ok, pid_t(), WaitStatus :: [waitstatus()]} | {error, posix()}.
-spec waitpid(
alcove_drv:ref(), [pid_t()], OSPid :: pid_t(), Options :: int32_t() | [constant()], timeout()
) ->
{ok, pid_t(), WaitStatus :: [waitstatus()]} | {error, posix()}.
-spec write(alcove_drv:ref(), [pid_t()], FD :: fd(), Buf :: iodata()) ->
{ok, Count :: ssize_t()} | {error, posix()}.
-spec write(alcove_drv:ref(), [pid_t()], FD :: fd(), Buf :: iodata(), timeout()) ->
{ok, Count :: ssize_t()} | {error, posix()}.
-spec version(alcove_drv:ref(), [pid_t()]) -> binary().
-spec version(alcove_drv:ref(), [pid_t()], timeout()) -> binary().
% Static functions
-export([
audit_arch/0,
wordalign/1,
wordalign/2,
define/3,
stdin/3,
stdout/2,
stdout/3,
stderr/2,
stderr/3,
eof/2,
eof/3,
event/2,
event/3,
filter/1,
filter/3,
getcpid/4
]).
% @doc Get seccomp system architecture
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> alcove:audit_arch().
% audit_arch_x86_64
% 3> alcove:define(Drv, [], alcove:audit_arch()).
% 3221225534
% '''
-spec audit_arch() -> atom().
audit_arch() ->
Arches = [
{{"armv6l", "linux", 4}, audit_arch_arm},
{{"armv7l", "linux", 4}, audit_arch_arm},
{{"i386", "linux", 4}, audit_arch_i386},
{{"aarch64", "linux", 8}, audit_arch_aarch64},
{{"x86_64", "linux", 8}, audit_arch_x86_64}
],
[Arch, _, OS | _] = string:tokens(
erlang:system_info(system_architecture),
"-"
),
Wordsize = erlang:system_info({wordsize, external}),
proplists:get_value({Arch, OS, Wordsize}, Arches, enotsup).
% @private
wordalign(Offset) ->
wordalign(Offset, erlang:system_info({wordsize, external})).
% @private
wordalign(Offset, Align) ->
(Align - (Offset rem Align)) rem Align.
% @doc Convert constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> alcove:define(Drv, [], clone_newns).
% 131072
% '''
-spec define(alcove_drv:ref(), [pid_t()], atom() | [atom()]) -> integer().
define(Drv, Pipeline, Constant) when is_atom(Constant) ->
define(Drv, Pipeline, [Constant]);
define(Drv, Pipeline, Constants) when is_list(Constants) ->
lists:foldl(
fun
(Constant, Result) when is_atom(Constant) ->
Val = define_constant(Drv, Pipeline, Constant),
Result bxor Val;
(Val, Result) when is_integer(Val) ->
Result bxor Val
end,
0,
Constants
).
define_constant(Drv, Pipeline, Constant) ->
Fun = [
fun clone_constant/3,
fun fcntl_constant/3,
fun file_constant/3,
fun ioctl_constant/3,
fun mount_constant/3,
fun prctl_constant/3,
fun rlimit_constant/3,
fun signal_constant/3,
fun syscall_constant/3
],
define_foreach(Drv, Pipeline, Constant, Fun).
define_foreach(_Drv, _Pipeline, Constant, []) ->
erlang:error({unknown, Constant});
define_foreach(Drv, Pipeline, Constant, [Fun | Rest]) ->
try Fun(Drv, Pipeline, Constant) of
unknown ->
define_foreach(Drv, Pipeline, Constant, Rest);
Val when is_integer(Val) ->
Val
catch
% Function call not supported on this platform
error:undef ->
define_foreach(Drv, Pipeline, Constant, Rest)
end.
% @doc Send data to stdin of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat"]).
% ok
% 4> alcove:stdin(Drv, [Pid], "testn").
% ok
% 5> alcove:stdout(Drv, [Pid]).
% [<<"testn">>]
% '''
-spec stdin(alcove_drv:ref(), [pid_t()], iodata()) -> ok.
stdin(Drv, Pids, Data) ->
case alcove_drv:stdin(Drv, Pids, Data) of
ok ->
ok;
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Data])
end.
% @doc Read stdout from the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat"]).
% ok
% 4> alcove:stdin(Drv, [Pid], "testn").
% ok
% 5> alcove:stdout(Drv, [Pid]).
% [<<"testn">>]
% '''
-spec stdout(alcove_drv:ref(), [pid_t()]) -> [binary()].
stdout(Drv, Pids) ->
stdout(Drv, Pids, 0).
-spec stdout(alcove_drv:ref(), [pid_t()], timeout()) -> [binary()].
stdout(Drv, Pids, Timeout) ->
stdout_1(Drv, Pids, Timeout, []).
stdout_1(Drv, Pids, Timeout, Acc) ->
case alcove_drv:stdout(Drv, Pids, Timeout) of
false ->
lists:reverse(Acc);
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
{alcove_pipe, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply ->
stdout_1(Drv, Pids, Timeout, [Reply | Acc])
end.
% @doc Read stderr from the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat", "/nonexistent"]).
% ok
% 4> alcove:stderr(Drv, [Pid]).
% [<<"cat: /nonexistent: No such file or directoryn">>]
% '''
-spec stderr(alcove_drv:ref(), [pid_t()]) -> [binary()].
stderr(Drv, Pids) ->
stderr(Drv, Pids, 0).
-spec stderr(alcove_drv:ref(), [pid_t()], timeout()) -> [binary()].
stderr(Drv, Pids, Timeout) ->
stderr_1(Drv, Pids, Timeout, []).
stderr_1(Drv, Pids, Timeout, Acc) ->
case alcove_drv:stderr(Drv, Pids, Timeout) of
false ->
lists:reverse(Acc);
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
{alcove_pipe, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply ->
stderr_1(Drv, Pids, Timeout, [Reply | Acc])
end.
% @doc Close stdin of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat"]).
% ok
% 4> alcove:eof(Drv, [Pid]).
% ok
% 5> alcove:event(Drv, [Pid]).
% {exit_status,0}
% '''
-spec eof(alcove_drv:ref(), [pid_t()]) -> ok | {error, posix()}.
eof(Drv, Pids) ->
eof(Drv, Pids, stdin).
% @doc Close stdin, stdout or stderr of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat"]).
% ok
% 4> alcove:eof(Drv, [Pid], stdin).
% ok
% 5> alcove:event(Drv, [Pid]).
% {exit_status,0}
% '''
-spec eof(alcove_drv:ref(), [pid_t()], stdin | stdout | stderr) ->
ok | {error, posix()}.
eof(_Drv, [], _Stdio) ->
{error, esrch};
eof(Drv, Pids, Stdio) ->
[Pid | Rest] = lists:reverse(Pids),
Pipeline = lists:reverse(Rest),
Proc = cpid(Drv, Pipeline),
case lists:keyfind(Pid, 2, Proc) of
false ->
{error, esrch};
N ->
eof_1(Drv, Pipeline, N, Stdio)
end.
eof_1(Drv, Pids, #alcove_pid{stdin = FD}, stdin) ->
close(Drv, Pids, FD);
eof_1(Drv, Pids, #alcove_pid{stdout = FD}, stdout) ->
close(Drv, Pids, FD);
eof_1(Drv, Pids, #alcove_pid{stderr = FD}, stderr) ->
close(Drv, Pids, FD).
% @doc Get events generated by alcove port process
%
% event/1,2 is used to retrieve async messages returned from the
% port, such as caught signals, the exit status or the termination
% signal.
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:kill(Drv, [], Pid, 15).
% ok
% 4> alcove:event(Drv, [Pid]).
% {signal,sigterm,
% <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,74,0,0,0,0,0,0,0,
% 0,...>>}
% '''
-spec event(alcove_drv:ref(), [pid_t()]) -> term().
event(Drv, Pids) ->
event(Drv, Pids, 0).
% @doc Get events generated by alcove port process
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:kill(Drv, [], Pid, 15).
% ok
% 4> alcove:event(Drv, [Pid], 5000).
% {signal,sigterm,
% <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,74,0,0,0,0,0,0,0,
% 0,...>>}
% 5> alcove:event(Drv, [Pid], 5000).
% false
% '''
-spec event(alcove_drv:ref(), [pid_t()], timeout()) -> term().
event(Drv, Pids, Timeout) ->
alcove_drv:event(Drv, Pids, Timeout).
% @doc Create a call filter list
%
% Generate a list of calls to filter for filter/3,4. By default, calls
% are blocked. To restrict the alcove control process to a subset of
% calls, use the allow tuple:
%
% ```
% # alcove process restricted to fork, clone, getpid
% alcove:filter({allow, [fork, clone, getpid]})
% '''
%
% == Examples ==
% ```
% 1> alcove:filter({allow, [fork, clone, getpid]}).
% <<255,223,255,239,239,255,255,255,255,255,255,255,15>>
% 2> alcove:filter([fork, clone, getpid]).
% <<0,32,0,16,16>>
% 3> alcove:filter({deny, [fork, clone, getpid]}).
% <<0,32,0,16,16>>
% '''
-spec filter(filter()) -> binary().
filter(Calls) when is_list(Calls) ->
filter({deny, Calls});
filter({allow, Calls}) when is_list(Calls) ->
Filter = [
alcove_proto:call(Call)
|| Call <-
alcove_proto:calls() -- Calls
],
filter_encode(Filter);
filter({deny, []}) ->
<<>>;
filter({deny, Calls}) when is_list(Calls) ->
Filter = [
alcove_proto:call(Call)
|| Call <-
sets:to_list(sets:from_list(Calls))
],
filter_encode(Filter).
filter_encode(Filter) ->
binary:encode_unsigned(
lists:foldl(fun(Call, N) -> N bxor (1 bsl Call) end, 0, Filter),
little
).
% @doc Restrict calls available to an alcove control process
%
% filter/3 restrict calls available to an alcove control process. Restricted
% control processes continue to proxy data and monitor and reap
% subprocesses.
%
% Invoking a filtered call will crash the process with 'undef'.
%
% If the filter call is filtered, subsequent calls to filter/3,4 will fail.
%
% Once added, the call cannot be removed from the filter set. Passing an
% empty binary (`<<>>') will not modify the current filter set.
%
% Filters are inherited by the child process from the parent. filter/3
% specifies the subprocess should use the same filter as the parent:
%
% ```
% 1> catch_exception(true).
% false
% 2> {ok, Drv} = alcove_drv:start().
% {ok,<0.179.0>}
% 3> {ok, Pid} = alcove:fork(Drv, []).
% {ok,16464}
% 4> Filter = alcove:filter([fork]).
% <<0,0,0,16>>
% % equivalent to: alcove:filter(Drv, [], Filter, Filter)
% 5> alcove:filter(Drv, [], Filter).
% ok
% 6> alcove:fork(Drv, [Pid]).
% * exception error: undefined function alcove:fork/2
% '''
-spec filter(alcove_drv:ref(), [pid_t()], binary()) -> ok | {error, einval}.
filter(Drv, Pids, Calls) ->
filter(Drv, Pids, Calls, Calls).
% @doc Get control process attributes
%
% Retrieves attributes set by the alcove control process for a
% child process.
%
% • flowcontrol
%
% Number of messages allowed from process:
%
% -1 : flowcontrol disabled
%
% 0 : stdout/stderr for process is not read
%
% 1+ : read this many messages from the process
%
% • signaloneof
%
% Signal sent to child process on shutdown.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,3925}
% 3> alcove:getcpid(Drv, [], Pid, flowcontrol).
% -1
% '''
-spec getcpid(alcove_drv:ref(), [pid_t()], pid_t(), alcove_pid_field()) -> false | int32_t().
getcpid(Drv, Pids, Pid, Key) ->
N = indexof(Key, record_info(fields, alcove_pid)),
case lists:keyfind(Pid, #alcove_pid.pid, alcove:cpid(Drv, Pids)) of
false ->
false;
Child when is_integer(N) ->
element(N, Child)
end.
indexof(El, List) ->
indexof(El, List, 2).
indexof(_El, [], _N) ->
false;
indexof(El, [El | _], N) ->
N;
indexof(El, [_ | Tail], N) ->
indexof(El, Tail, N + 1).
% @private
% @doc Allocate memory
%
% Test memory allocation.
%
% Memory is allocated using a cstruct which is a list containing:
%
% • binary: a value to be allocated and initialized in the memory
%
% • {ptr, integer()}: create a pointer to 0 initialized memory
%
% • {ptr, binary()}: create a pointer to memory initialized to the binary
%
% The return value is an ok tuple:
%
% • the atom ok
%
% • a binary with the raw memory
%
% • an initialized cstruct
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.182.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,4040}
% 3> alcove:alloc(Drv, [Pid], [<<"initialized">>, {ptr, 16}, {ptr, <<"initialized">>}]).
% {ok,<<105,110,105,116,105,97,108,105,122,101,100,48,238,
% 23,162,165,87,0,0,80,238,23,162,165,87,0,0>>,
% [<<"initialized">>,
% {ptr,<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>},
% {ptr,<<"initialized">>}]}
%
% % <<"initialized">>: 105,110,105,116,105,97,108,105,122,101,100
% % {ptr,<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>}: 48,238,23,162,165,87,0,0 (pointer)
% % {ptr,<<"initialized">>}: 80,238,23,162,165,87,0,0 (pointer)
% '''
alloc(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, alloc, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @private
% @doc Allocate memory
%
% Test memory allocation.
%
% Memory is allocated using a cstruct which is a list containing:
%
% • binary: a value to be allocated and initialized in the memory
%
% • {ptr, integer()}: create a pointer to 0 initialized memory
%
% • {ptr, binary()}: create a pointer to memory initialized to the binary
%
% The return value is an ok tuple:
%
% • the atom ok
%
% • a binary with the raw memory
%
% • an initialized cstruct
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.182.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,4040}
% 3> alcove:alloc(Drv, [Pid], [<<"initialized">>, {ptr, 16}, {ptr, <<"initialized">>}]).
% {ok,<<105,110,105,116,105,97,108,105,122,101,100,48,238,
% 23,162,165,87,0,0,80,238,23,162,165,87,0,0>>,
% [<<"initialized">>,
% {ptr,<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>},
% {ptr,<<"initialized">>}]}
%
% % <<"initialized">>: 105,110,105,116,105,97,108,105,122,101,100
% % {ptr,<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>}: 48,238,23,162,165,87,0,0 (pointer)
% % {ptr,<<"initialized">>}: 80,238,23,162,165,87,0,0 (pointer)
% '''
alloc(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, alloc, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc Convert capsicum constants to integer
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.208.0>}
% 2> alcove:cap_constant(Drv, [], cap_fcntl_setfl).
% 16
% '''
cap_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
cap_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert capsicum constants to integer
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.208.0>}
% 2> alcove:cap_constant(Drv, [], cap_fcntl_setfl).
% 16
% '''
cap_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
cap_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc cap_enter(2): place process into capability mode
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.208.0>}
% 2> {ok, Pid1} = alcove:fork(Drv, []).
% {ok,75331}
% 3> {ok, Pid2} = alcove:fork(Drv, []).
% {ok,75332}
% 4> ok = alcove:cap_enter(Drv, [Pid1]).
% ok
% 5> alcove:kill(Drv, [Pid1], 0, 0).
% {error,ecapmode}
% 6> alcove:kill(Drv, [Pid2], 0, 0).
% ok
% 7> alcove:kill(Drv, [], 0, 0).
% ok
% '''
cap_enter(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, cap_enter, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc cap_enter(2): place process into capability mode
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.208.0>}
% 2> {ok, Pid1} = alcove:fork(Drv, []).
% {ok,75331}
% 3> {ok, Pid2} = alcove:fork(Drv, []).
% {ok,75332}
% 4> ok = alcove:cap_enter(Drv, [Pid1]).
% ok
% 5> alcove:kill(Drv, [Pid1], 0, 0).
% {error,ecapmode}
% 6> alcove:kill(Drv, [Pid2], 0, 0).
% ok
% 7> alcove:kill(Drv, [], 0, 0).
% ok
% '''
cap_enter(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, cap_enter, [], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc cap_fcntls_get(2): get allowed fcntl commands in capability mode
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,77853}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> ok = alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_fcntls_get(Drv, [Pid], FD).
% {ok,120}
% '''
cap_fcntls_get(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
cap_fcntls_get,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc cap_fcntls_get(2): get allowed fcntl commands in capability mode
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,77853}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> ok = alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_fcntls_get(Drv, [Pid], FD).
% {ok,120}
% '''
cap_fcntls_get(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
cap_fcntls_get,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc cap_fcntls_limit(2): manage fcntl commands in capability mode
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,77853}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> ok = alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_fcntls_get(Drv, [Pid], FD).
% {ok,120}
% 6> ok = alcove:cap_fcntls_limit(Drv, [Pid], FD, [cap_fcntl_setfl]).
% ok
% 7> alcove:cap_fcntls_get(Drv, [Pid], FD).
% {ok,16}
% '''
cap_fcntls_limit(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
cap_fcntls_limit,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc cap_fcntls_limit(2): manage fcntl commands in capability mode
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,77853}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> ok = alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_fcntls_get(Drv, [Pid], FD).
% {ok,120}
% 6> ok = alcove:cap_fcntls_limit(Drv, [Pid], FD, [cap_fcntl_setfl]).
% ok
% 7> alcove:cap_fcntls_get(Drv, [Pid], FD).
% {ok,16}
% '''
cap_fcntls_limit(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
cap_fcntls_limit,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc cap_getmode(2): check if capability mode is enabled
%
% • `0' : false
%
% • `1' : true
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> ok = alcove:cap_enter(Drv, [Pid]).
% ok
% 4> alcove:cap_getmode(Drv, [Pid]).
% {ok,1}
% 5> alcove:cap_getmode(Drv, []).
% {ok,0}
% '''
cap_getmode(Drv, Pids) ->
case alcove_drv:call(Drv,
Pids,
cap_getmode,
[],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc cap_getmode(2): check if capability mode is enabled
%
% • `0' : false
%
% • `1' : true
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> ok = alcove:cap_enter(Drv, [Pid]).
% ok
% 4> alcove:cap_getmode(Drv, [Pid]).
% {ok,1}
% 5> alcove:cap_getmode(Drv, []).
% {ok,0}
% '''
cap_getmode(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv,
Pids,
cap_getmode,
[],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc cap_ioctls_limit(2): manage allowed ioctl commands
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/dev/pts/1", [o_rdwr, o_nonblock], 0).
% {ok,6}
% 4> alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_ioctls_limit(Drv, [Pid], FD, [tiocmget, tiocgwinsz]).
% ok
% 6> alcove:ioctl(Drv, [Pid], FD, tiocmset, <<>>).
% {error,enotcapable}
% 7> alcove:ioctl(Drv, [Pid], FD, tiocmget, <<>>).
% {ok,0,<<>>}
% '''
cap_ioctls_limit(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
cap_ioctls_limit,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc cap_ioctls_limit(2): manage allowed ioctl commands
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/dev/pts/1", [o_rdwr, o_nonblock], 0).
% {ok,6}
% 4> alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_ioctls_limit(Drv, [Pid], FD, [tiocmget, tiocgwinsz]).
% ok
% 6> alcove:ioctl(Drv, [Pid], FD, tiocmset, <<>>).
% {error,enotcapable}
% 7> alcove:ioctl(Drv, [Pid], FD, tiocmget, <<>>).
% {ok,0,<<>>}
% '''
cap_ioctls_limit(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
cap_ioctls_limit,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc cap_rights_limit(2): manage process capabilities
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_rights_limit(Drv, [Pid], FD, [cap_read]).
% ok
% 6> alcove:read(Drv, [Pid], FD, 64).
% {ok,<<"# $FreeBSD$\n#\nroot:*:0:0:Charlie &:/root:/bin/csh\ntoor:*:0:0:Bou">>}
% 7> alcove:lseek(Drv, [Pid], FD, 0, 0).
% {error,enotcapable}
% 8> alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {error,ecapmode}
% '''
cap_rights_limit(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
cap_rights_limit,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc cap_rights_limit(2): manage process capabilities
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> alcove:cap_enter(Drv, [Pid]).
% ok
% 5> alcove:cap_rights_limit(Drv, [Pid], FD, [cap_read]).
% ok
% 6> alcove:read(Drv, [Pid], FD, 64).
% {ok,<<"# $FreeBSD$\n#\nroot:*:0:0:Charlie &:/root:/bin/csh\ntoor:*:0:0:Bou">>}
% 7> alcove:lseek(Drv, [Pid], FD, 0, 0).
% {error,enotcapable}
% 8> alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {error,ecapmode}
% '''
cap_rights_limit(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
cap_rights_limit,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc chdir(2): change process current working directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18617}
% 3> alcove:chdir(Drv, [Pid], "/tmp").
% ok
% 4> alcove:chdir(Drv, [], "/").
% ok
% 5> alcove:getcwd(Drv, [Pid]).
% {ok,<<"/tmp">>}
% 6> alcove:getcwd(Drv, []).
% {ok,<<"/">>}
% '''
chdir(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, chdir, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc chdir(2): change process current working directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18617}
% 3> alcove:chdir(Drv, [Pid], "/tmp").
% ok
% 4> alcove:chdir(Drv, [], "/").
% ok
% 5> alcove:getcwd(Drv, [Pid]).
% {ok,<<"/tmp">>}
% 6> alcove:getcwd(Drv, []).
% {ok,<<"/">>}
% '''
chdir(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, chdir, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc chmod(2): change file permissions
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/foo123.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 4> alcove:chmod(Drv, [Pid], "/tmp/foo123.txt", 8#400).
% ok
% '''
chmod(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
chmod,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc chmod(2): change file permissions
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/foo123.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 4> alcove:chmod(Drv, [Pid], "/tmp/foo123.txt", 8#400).
% ok
% '''
chmod(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
chmod,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc chown(2): change file ownership
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/foo123.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 6> alcove:chown(Drv, [Pid], "/tmp/foo123.txt", 0, 0).
% ok
% '''
chown(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
chown,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc chown(2): change file ownership
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/foo123.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 6> alcove:chown(Drv, [Pid], "/tmp/foo123.txt", 0, 0).
% ok
% '''
chown(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
chown,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc chroot(2): change root directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:chroot(Drv, [Pid], "/tmp").
% ok
% 4> alcove:chdir(Drv, [Pid], "/").
% ok
% 5> alcove:getcwd(Drv, [Pid]).
% {ok,<<"/">>}
% '''
chroot(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
chroot,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc chroot(2): change root directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:chroot(Drv, [Pid], "/tmp").
% ok
% 4> alcove:chdir(Drv, [Pid], "/").
% ok
% 5> alcove:getcwd(Drv, [Pid]).
% {ok,<<"/">>}
% '''
chroot(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, chroot, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc clearenv(3): zero process environment
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:clearenv(Drv, [Pid]).
% ok
% 4> alcove:environ(Drv, [Pid]).
% []
% '''
clearenv(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, clearenv, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc clearenv(3): zero process environment
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:clearenv(Drv, [Pid]).
% ok
% 4> alcove:environ(Drv, [Pid]).
% []
% '''
clearenv(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, clearenv, [], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc clone(2): create a new process
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns, clone_newpid, clone_newipc, clone_newuts, clone_newnet]).
% {ok,19127}
% 3> alcove:getpid(Drv, [Pid]).
% 1
% '''
clone(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, clone, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc clone(2): create a new process
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns, clone_newpid, clone_newipc, clone_newuts, clone_newnet]).
% {ok,19127}
% 3> alcove:getpid(Drv, [Pid]).
% 1
% '''
clone(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, clone, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc Map clone(2) symbols to integer constants
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:clone_constant(Drv, [19127], clone_newuts).
% 67108864
% '''
clone_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
clone_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Map clone(2) symbols to integer constants
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,19048}
% 3> alcove:clone_constant(Drv, [19127], clone_newuts).
% 67108864
% '''
clone_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
clone_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc close(2): close a file descriptor
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/foo123.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 4> alcove:close(Drv, [Pid], FD).
% ok
% '''
close(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, close, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc close(2): close a file descriptor
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/foo123.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 4> alcove:close(Drv, [Pid], FD).
% ok
% '''
close(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, close, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc connect(2): initiate a connection on a socket
%
% == Examples ==
%
% ```
% •module(unix_socket).
%
% •export([connect]).
%
% connect(Data) when is_binary(Data) ->
% {ok, Drv} = alcove:start(),
% {ok, NC} = alcove:fork(Drv, []),
% {ok, Process} = alcove:fork(Drv, []),
%
% Sockname = <<"/tmp/test.", (integer_to_binary(alcove:getpid(Drv, [])))/binary>>,
% ok = alcove:execvp(Drv, [NC], "nc", ["nc", "-l", "-U", Sockname]),
%
% ok = waitfor(Sockname),
%
% {ok, Socket} = alcove:socket(Drv, [Process], af_unix, sock_stream, 0),
%
% % #define UNIX_PATH_MAX 108
% % struct sockaddr_un {
% % __kernel_sa_family_t sun_family; /* AF_UNIX */
% % char sun_path[UNIX_PATH_MAX]; /* pathname */
% % };
% AF_UNIX = 1,
% SocknameLen = byte_size(Sockname),
% Len = (unix_path_max() - SocknameLen) * 8,
% ok = alcove:connect(Drv, [Process], Socket, [
% sockaddr_common(AF_UNIX, SocknameLen),
% Sockname,
% <<0:Len>>
% ]),
%
% % alcove process -> nc
% {ok, N} = alcove:write(Drv, [Process], Socket, Data),
% receive
% {alcove_stdout, Drv, [NC], Stdout} ->
% Stdout
% end.
%
% % UNIX_PATH_MAX
% unix_path_max() ->
% case erlang:system_info(os_type) of
% {unix, BSD} when BSD == darwin; BSD == openbsd; BSD == netbsd; BSD == freebsd ->
% 104;
% {unix, _} ->
% 108
% end.
%
% % struct sockaddr
% sockaddr_common(Family, Length) ->
% case erlang:system_info(os_type) of
% {unix, BSD} when BSD == darwin; BSD == openbsd; BSD == netbsd; BSD == freebsd ->
% <<Length:8, Family:8>>;
% {unix, _} ->
% <<Family:16/native>>
% end.
%
% waitfor(Sockname) ->
% case file:read_file_info(Sockname) of
% {ok, _} ->
% ok;
% {error, enoent} ->
% timer:sleep(1),
% waitfor(Sockname);
% {error, eperm} ->
% ok;
% Error ->
% Error
% end.
% '''
connect(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
connect,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc connect(2): initiate a connection on a socket
%
% == Examples ==
%
% ```
% •module(unix_socket).
%
% •export([connect]).
%
% connect(Data) when is_binary(Data) ->
% {ok, Drv} = alcove:start(),
% {ok, NC} = alcove:fork(Drv, []),
% {ok, Process} = alcove:fork(Drv, []),
%
% Sockname = <<"/tmp/test.", (integer_to_binary(alcove:getpid(Drv, [])))/binary>>,
% ok = alcove:execvp(Drv, [NC], "nc", ["nc", "-l", "-U", Sockname]),
%
% ok = waitfor(Sockname),
%
% {ok, Socket} = alcove:socket(Drv, [Process], af_unix, sock_stream, 0),
%
% % #define UNIX_PATH_MAX 108
% % struct sockaddr_un {
% % __kernel_sa_family_t sun_family; /* AF_UNIX */
% % char sun_path[UNIX_PATH_MAX]; /* pathname */
% % };
% AF_UNIX = 1,
% SocknameLen = byte_size(Sockname),
% Len = (unix_path_max() - SocknameLen) * 8,
% ok = alcove:connect(Drv, [Process], Socket, [
% sockaddr_common(AF_UNIX, SocknameLen),
% Sockname,
% <<0:Len>>
% ]),
%
% % alcove process -> nc
% {ok, N} = alcove:write(Drv, [Process], Socket, Data),
% receive
% {alcove_stdout, Drv, [NC], Stdout} ->
% Stdout
% end.
%
% % UNIX_PATH_MAX
% unix_path_max() ->
% case erlang:system_info(os_type) of
% {unix, BSD} when BSD == darwin; BSD == openbsd; BSD == netbsd; BSD == freebsd ->
% 104;
% {unix, _} ->
% 108
% end.
%
% % struct sockaddr
% sockaddr_common(Family, Length) ->
% case erlang:system_info(os_type) of
% {unix, BSD} when BSD == darwin; BSD == openbsd; BSD == netbsd; BSD == freebsd ->
% <<Length:8, Family:8>>;
% {unix, _} ->
% <<Family:16/native>>
% end.
%
% waitfor(Sockname) ->
% case file:read_file_info(Sockname) of
% {ok, _} ->
% ok;
% {error, enoent} ->
% timer:sleep(1),
% waitfor(Sockname);
% {error, eperm} ->
% ok;
% Error ->
% Error
% end.
% '''
connect(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
connect,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc Returns the list of child PIDs for this process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid1} = alcove:fork(Drv, []).
% {ok,19048}
% 3> {ok, Pid2} = alcove:fork(Drv, []).
% {ok,19127}
% 4> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 5> alcove:cpid(Drv, [Pid1]).
% []
% 6> alcove:cpid(Drv, []).
% [#alcove_pid{pid = 19048,flowcontrol = -1,signaloneof = 15,
% fdctl = 7,stdin = 9,stdout = 10,stderr = 12},
% #alcove_pid{pid = 19127,flowcontrol = -1,signaloneof = 15,
% fdctl = 8,stdin = 13,stdout = 14,stderr = 16}]
% '''
cpid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, cpid, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc Returns the list of child PIDs for this process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid1} = alcove:fork(Drv, []).
% {ok,19048}
% 3> {ok, Pid2} = alcove:fork(Drv, []).
% {ok,19127}
% 4> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 5> alcove:cpid(Drv, [Pid1]).
% []
% 6> alcove:cpid(Drv, []).
% [#alcove_pid{pid = 19048,flowcontrol = -1,signaloneof = 15,
% fdctl = 7,stdin = 9,stdout = 10,stderr = 12},
% #alcove_pid{pid = 19127,flowcontrol = -1,signaloneof = 15,
% fdctl = 8,stdin = 13,stdout = 14,stderr = 16}]
% '''
cpid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, cpid, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc environ(7): return the process environment variables
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> alcove:environ(Drv, []).
% [<<"LANG=C.UTF-8">>,
% <<"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin">>,
% <<"TERM=screen">>, <<"SHELL=/bin/bash">>]
% '''
environ(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, environ, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc environ(7): return the process environment variables
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> alcove:environ(Drv, []).
% [<<"LANG=C.UTF-8">>,
% <<"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin">>,
% <<"TERM=screen">>, <<"SHELL=/bin/bash">>]
% '''
environ(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, environ, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc Convert errno integer to atom
%
% == Examples ==
%
% ```
% 1> alcove:errno_id(Drv, [], 1).
% eperm
% '''
errno_id(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
errno_id,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert errno integer to atom
%
% == Examples ==
%
% ```
% 1> alcove:errno_id(Drv, [], 1).
% eperm
% '''
errno_id(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
errno_id,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc execve(2): replace process image with environment
%
% Replace the process image, specifying the environment for the new
% process image.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,29037}
% 3> alcove:execve(Drv, [Pid], "/usr/bin/env", ["env"], ["FOO=123"]).
% ok
%
% % Shell got {alcove_stdout,<0.176.0>,[29037],<<"FOO=123\n">>}
% % Shell got {alcove_event,<0.176.0>,[29037],{exit_status,0}}
%
% 4> alcove:stdout(Drv, [Pid]).
% [<<"FOO=123\n">>]
% 5> alcove:event(Drv, [Pid], 5000).
% {exit_status,0}
% ok
% '''
execve(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
execve,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc execve(2): replace process image with environment
%
% Replace the process image, specifying the environment for the new
% process image.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,29037}
% 3> alcove:execve(Drv, [Pid], "/usr/bin/env", ["env"], ["FOO=123"]).
% ok
%
% % Shell got {alcove_stdout,<0.176.0>,[29037],<<"FOO=123\n">>}
% % Shell got {alcove_event,<0.176.0>,[29037],{exit_status,0}}
%
% 4> alcove:stdout(Drv, [Pid]).
% [<<"FOO=123\n">>]
% 5> alcove:event(Drv, [Pid], 5000).
% {exit_status,0}
% ok
% '''
execve(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
execve,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc execvp(2): replace the current process image using the search path
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,29087}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat"]).
% ok
% 4> alcove:stdin(Drv, [Pid], "test\n").
% ok
% 5> alcove:stdout(Drv, [Pid]).
% [<<"test\n">>]
% 6> alcove:stdin(Drv, [Pid], "123\n").
% ok
% 7> flush().
% Shell got {alcove_stdout,<0.176.0>,[29087],<<"123\n">>}
% ok
% '''
execvp(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
execvp,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc execvp(2): replace the current process image using the search path
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,29087}
% 3> alcove:execvp(Drv, [Pid], "cat", ["cat"]).
% ok
% 4> alcove:stdin(Drv, [Pid], "test\n").
% ok
% 5> alcove:stdout(Drv, [Pid]).
% [<<"test\n">>]
% 6> alcove:stdin(Drv, [Pid], "123\n").
% ok
% 7> flush().
% Shell got {alcove_stdout,<0.176.0>,[29087],<<"123\n">>}
% ok
% '''
execvp(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
execvp,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc exit(3): cause an alcove control process to exit
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,30973}
% 3> alcove:exit(Drv, [Pid], 111).
% ok
% 4> flush().
% Shell got {alcove_event,<0.176.0>,[30973],{exit_status,111}}
% ok
% '''
exit(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, exit, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc exit(3): cause an alcove control process to exit
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,30973}
% 3> alcove:exit(Drv, [Pid], 111).
% ok
% 4> flush().
% Shell got {alcove_event,<0.176.0>,[30973],{exit_status,111}}
% ok
% '''
exit(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, exit, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc fcntl(2): perform operations on a file descriptor
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,31012}
%
% % stdin = 0
% 3> alcove:fcntl(Drv, [Pid], 0, f_getfd, 0).
% {ok,0}
% '''
fcntl(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
fcntl,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc fcntl(2): perform operations on a file descriptor
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.176.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,31012}
%
% % stdin = 0
% 3> alcove:fcntl(Drv, [Pid], 0, f_getfd, 0).
% {ok,0}
% '''
fcntl(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
fcntl,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc Convert fnctl(2) constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> alcove:fcntl_constant(Drv, [], fd_cloexec).
% 1
% '''
fcntl_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
fcntl_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert fnctl(2) constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.176.0>}
% 2> alcove:fcntl_constant(Drv, [], fd_cloexec).
% 1
% '''
fcntl_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
fcntl_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc fexecve(2): replace the process image
%
% Replace the process image, specifying the environment for the new process
% image, using a previously opened file descriptor. The file descriptor
% can be set to close after exec() by passing the O_CLOEXEC flag to open:
%
% ```
% {ok, Pid} = alcove:fork(Drv, []),
% {ok, FD} = alcove:open(Drv, [Pid], "/bin/ls", [o_rdonly,o_cloexec], 0),
% ok = alcove:fexecve(Drv, [Pid], FD, ["ls", "-al"], ["FOO=123"]).
% '''
%
% Linux requires an environment to be set unlike with execve(2). The
% environment can be empty:
%
% ```
% % Environment required on Linux
% ok = alcove:fexecve(Drv, [Pid], FD, ["ls", "-al"], [""]).
% '''
%
% == Support ==
%
% • Linux
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,31491}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/usr/bin/env", [o_rdonly,o_cloexec], 0).
% {ok,6}
% 4> alcove:fexecve(Drv, [Pid], FD, ["env", "-0"], ["FOO=123"]).
% ok
% 5> flush().
% Shell got {alcove_stdout,<0.177.0>,[31491],<<70,79,79,61,49,50,51,0>>}
% Shell got {alcove_event,<0.177.0>,[31491],{exit_status,0}}
% ok
% '''
fexecve(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
fexecve,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc fexecve(2): replace the process image
%
% Replace the process image, specifying the environment for the new process
% image, using a previously opened file descriptor. The file descriptor
% can be set to close after exec() by passing the O_CLOEXEC flag to open:
%
% ```
% {ok, Pid} = alcove:fork(Drv, []),
% {ok, FD} = alcove:open(Drv, [Pid], "/bin/ls", [o_rdonly,o_cloexec], 0),
% ok = alcove:fexecve(Drv, [Pid], FD, ["ls", "-al"], ["FOO=123"]).
% '''
%
% Linux requires an environment to be set unlike with execve(2). The
% environment can be empty:
%
% ```
% % Environment required on Linux
% ok = alcove:fexecve(Drv, [Pid], FD, ["ls", "-al"], [""]).
% '''
%
% == Support ==
%
% • Linux
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,31491}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/usr/bin/env", [o_rdonly,o_cloexec], 0).
% {ok,6}
% 4> alcove:fexecve(Drv, [Pid], FD, ["env", "-0"], ["FOO=123"]).
% ok
% 5> flush().
% Shell got {alcove_stdout,<0.177.0>,[31491],<<70,79,79,61,49,50,51,0>>}
% Shell got {alcove_event,<0.177.0>,[31491],{exit_status,0}}
% ok
% '''
fexecve(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
fexecve,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc Constants for open(2)
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:file_constant(Drv, [], o_rdonly).
% 0
% '''
file_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
file_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Constants for open(2)
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:file_constant(Drv, [], o_rdonly).
% 0
% '''
file_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
file_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc Restrict available calls for control and subprocess
%
% filter/4 allows setting different filters for the control and
% subprocesses:
%
% == Examples ==
%
% ```
% 1> catch_exception(true).
% false
% 2> {ok, Drv} = alcove_drv:start().
% {ok,<0.189.0>}
% 3> F1 = alcove:filter({allow, [fork,filter,getcwd]}).
% <<255,255,255,231,239,255,255,255,255,255,255,255,15>>
% 4> F2 = alcove:filter({allow, [getpid,gethostname]}).
% <<255,255,255,223,237,255,255,255,255,255,255,255,15>>
% % Control process: restricted to: fork, filter, getcwd
% % Any forked control subprocess: restricted to: getpid, gethostname
% 5> alcove:filter(Drv, [], F1, F2).
% ok
% 6> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18721}
% 7> alcove:getpid(Drv, [Pid]).
% 18721
% 8> alcove:getpid(Drv, []).
% * exception error: undefined function alcove:getpid/2
% 9> alcove:getcwd(Drv, [Pid]).
% * exception error: undefined function alcove:getcwd/2
% 10> alcove:getcwd(Drv, []).
% {ok, <<"/">>}
% '''
filter(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
filter,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc Restrict available calls for control and subprocess
%
% filter/4 allows setting different filters for the control and
% subprocesses:
%
% == Examples ==
%
% ```
% 1> catch_exception(true).
% false
% 2> {ok, Drv} = alcove_drv:start().
% {ok,<0.189.0>}
% 3> F1 = alcove:filter({allow, [fork,filter,getcwd]}).
% <<255,255,255,231,239,255,255,255,255,255,255,255,15>>
% 4> F2 = alcove:filter({allow, [getpid,gethostname]}).
% <<255,255,255,223,237,255,255,255,255,255,255,255,15>>
% % Control process: restricted to: fork, filter, getcwd
% % Any forked control subprocess: restricted to: getpid, gethostname
% 5> alcove:filter(Drv, [], F1, F2).
% ok
% 6> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18721}
% 7> alcove:getpid(Drv, [Pid]).
% 18721
% 8> alcove:getpid(Drv, []).
% * exception error: undefined function alcove:getpid/2
% 9> alcove:getcwd(Drv, [Pid]).
% * exception error: undefined function alcove:getcwd/2
% 10> alcove:getcwd(Drv, []).
% {ok, <<"/">>}
% '''
filter(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
filter,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc fork(2): create a new process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.189.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18721}
% 3> alcove:getpid(Drv, [Pid]).
% 18721
% '''
fork(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, fork, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc fork(2): create a new process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.189.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18721}
% 3> alcove:getpid(Drv, [Pid]).
% 18721
% '''
fork(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, fork, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getcwd(3): return the current working directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,3925}
% 3> alcove:chdir(Drv, [Pid], "/").
% ok
% 4> alcove:getcwd(Drv, [Pid]).
% {ok,<<"/">>}
% '''
getcwd(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getcwd, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getcwd(3): return the current working directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,3925}
% 3> alcove:chdir(Drv, [Pid], "/").
% ok
% 4> alcove:getcwd(Drv, [Pid]).
% {ok,<<"/">>}
% '''
getcwd(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getcwd, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getenv(3): retrieve an environment variable
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getenv(Drv, [], "TERM").
% <<"screen">>
% '''
getenv(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
getenv,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc getenv(3): retrieve an environment variable
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getenv(Drv, [], "TERM").
% <<"screen">>
% '''
getenv(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, getenv, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc getgid(2): retrieve the process group ID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getgid(Drv, []).
% 1000
% '''
getgid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getgid, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getgid(2): retrieve the process group ID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getgid(Drv, []).
% 1000
% '''
getgid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getgid, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getgroups(2): retrieve the list of supplementary groups
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getgroups(Drv, []).
% {ok,[24,20,1000]}
% '''
getgroups(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getgroups, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getgroups(2): retrieve the list of supplementary groups
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getgroups(Drv, []).
% {ok,[24,20,1000]}
% '''
getgroups(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getgroups, [], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc gethostname(2): retrieve the system hostname
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:gethostname(Drv, []).
% {ok,<<"host1">>}
% '''
gethostname(Drv, Pids) ->
case alcove_drv:call(Drv,
Pids,
gethostname,
[],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc gethostname(2): retrieve the system hostname
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:gethostname(Drv, []).
% {ok,<<"host1">>}
% '''
gethostname(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv,
Pids,
gethostname,
[],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc Retrieve port options for event loop
%
% Options are configurable per process, with the default settings inherited
% from the parent.
%
% The initial values for these options are set for the port by
% alcove_drv:start/1.
%
% • maxchild : non_neg_integer() : 64
%
% Number of child processes allowed for this control process. The value
% can be modified using setopt/4,5. Additionally, reducing RLIMIT_NOFILE
% for the process may result in a reduced maxchild value.
%
% • exit_status : 1 | 0 : 1
%
% Controls whether the controlling Erlang process is informed of a
% process exit value.
%
% • maxforkdepth : non_neg_integer() : 16
%
% Sets the maximum length of the alcove process pipeline.
%
% • termsig : 1 | 0 : 1
%
% If a child process exits because of a signal, notify the controlling
% Erlang process.
%
% • flowcontrol : int32_t() : -1 (disabled)
%
% Sets the default flow control behaviour for a newly forked process. Flow
% control is applied after the child process calls exec().
%
% See setcpid/5.
%
% • signaloneof : 0-255 : 15
%
% Send a signal to a child process on shutdown (stdin of the alcove
% control process is closed).
%
% See setcpid/5.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getopt(Drv, [], maxforkdepth).
% 16
% '''
getopt(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
getopt,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Retrieve port options for event loop
%
% Options are configurable per process, with the default settings inherited
% from the parent.
%
% The initial values for these options are set for the port by
% alcove_drv:start/1.
%
% • maxchild : non_neg_integer() : 64
%
% Number of child processes allowed for this control process. The value
% can be modified using setopt/4,5. Additionally, reducing RLIMIT_NOFILE
% for the process may result in a reduced maxchild value.
%
% • exit_status : 1 | 0 : 1
%
% Controls whether the controlling Erlang process is informed of a
% process exit value.
%
% • maxforkdepth : non_neg_integer() : 16
%
% Sets the maximum length of the alcove process pipeline.
%
% • termsig : 1 | 0 : 1
%
% If a child process exits because of a signal, notify the controlling
% Erlang process.
%
% • flowcontrol : int32_t() : -1 (disabled)
%
% Sets the default flow control behaviour for a newly forked process. Flow
% control is applied after the child process calls exec().
%
% See setcpid/5.
%
% • signaloneof : 0-255 : 15
%
% Send a signal to a child process on shutdown (stdin of the alcove
% control process is closed).
%
% See setcpid/5.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getopt(Drv, [], maxforkdepth).
% 16
% '''
getopt(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, getopt, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc getpgrp(2): retrieve the process group
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getpgrp(Drv, []).
% 3924
% '''
getpgrp(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getpgrp, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getpgrp(2): retrieve the process group
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getpgrp(Drv, []).
% 3924
% '''
getpgrp(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getpgrp, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getpid(2): retrieve the system PID of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getpid(Drv, []).
% 3924
% '''
getpid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getpid, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getpid(2): retrieve the system PID of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getpid(Drv, []).
% 3924
% '''
getpid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getpid, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getpriority(2): retrieve scheduling priority of process, process group or user
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getpriority(Drv, [], prio_process, 0).
% {ok,0}
% '''
getpriority(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
getpriority,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc getpriority(2): retrieve scheduling priority of process, process group or user
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getpriority(Drv, [], prio_process, 0).
% {ok,0}
% '''
getpriority(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
getpriority,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc getresgid(2): get real, effective and saved group ID
%
% == Support ==
%
% • Linux
%
% • OpenBSD
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getresgid(Drv, []).
% {ok,1000,1000,1000}
% '''
getresgid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getresgid, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getresgid(2): get real, effective and saved group ID
%
% == Support ==
%
% • Linux
%
% • OpenBSD
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getresgid(Drv, []).
% {ok,1000,1000,1000}
% '''
getresgid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getresgid, [], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getresuid(2): get real, effective and saved user ID
%
% == Support ==
%
% • Linux
%
% • OpenBSD
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getresuid(Drv, []).
% {ok,1000,1000,1000}
% '''
getresuid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getresuid, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getresuid(2): get real, effective and saved user ID
%
% == Support ==
%
% • Linux
%
% • OpenBSD
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getresuid(Drv, []).
% {ok,1000,1000,1000}
% '''
getresuid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getresuid, [], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc getrlimit(2): retrieve the resource limits for a process
%
% Returns a record:
%
% ```
% -include_lib("alcove/include/alcove.hrl").
%
% #alcove_rlimit{
% cur = integer(),
% max = integer()
% }
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 3> alcove:getrlimit(Drv, [], rlimit_nofile).
% {ok,#alcove_rlimit{cur = 1024,max = 1048576}}
% '''
getrlimit(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
getrlimit,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc getrlimit(2): retrieve the resource limits for a process
%
% Returns a record:
%
% ```
% -include_lib("alcove/include/alcove.hrl").
%
% #alcove_rlimit{
% cur = integer(),
% max = integer()
% }
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 3> alcove:getrlimit(Drv, [], rlimit_nofile).
% {ok,#alcove_rlimit{cur = 1024,max = 1048576}}
% '''
getrlimit(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
getrlimit,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc getsid(2): retrieve the session ID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getsid(Drv, [], 0).
% {ok,3924}
% '''
getsid(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
getsid,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc getsid(2): retrieve the session ID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getsid(Drv, [], 0).
% {ok,3924}
% '''
getsid(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, getsid, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc getuid(2): returns the process user ID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getuid(Drv, []).
% 1000
% '''
getuid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, getuid, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc getuid(2): returns the process user ID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:getuid(Drv, []).
% 1000
% '''
getuid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, getuid, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc ioctl(2): control device
%
% Controls a device using a file descriptor previously obtained using
% open/5.
%
% Argp can be either a binary or a list representation of a C struct. See
% prctl/7 below for a description of the list elements.
%
% On success, ioctl/5 returns a 3-tuple:
%
% • Result: an integer equal to the return value of the ioctl
%
% Usually 0 but some ioctls may use the return value as the output
% parameter.
%
% • Bin: the value depends on the type of the input parameter Argp
%
% • cstruct: contains the contents of the memory pointed to by Argp
%
% • integer/binary: an empty binary
%
% == Examples ==
%
% An example of creating a tap device in a net namespace on Linux:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newnet]).
% {ok,8288}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/dev/net/tun", [o_rdwr], 0).
% {ok,6}
% 4> {ok, 0, <<"tap", _/binary>>} = alcove:ioctl(Drv, [Pid], FD, tunsetiff, <<
% 4> % generate a tuntap device name
% 4> 0:(16 * 8),
% 4> % IFF_TAP, IFF_NO_PI
% 4> (16#0002 bor 16#1000):2/native-unsigned-integer-unit:8,
% 4> 0:(14 * 8)
% 4> >>).
% {ok,0,
% <<116,97,112,48,0,0,0,0,0,0,0,0,0,0,0,0,2,16,0,0,0,0,0,0,
% 0,0,...>>}
% '''
ioctl(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
ioctl,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc ioctl(2): control device
%
% Controls a device using a file descriptor previously obtained using
% open/5.
%
% Argp can be either a binary or a list representation of a C struct. See
% prctl/7 below for a description of the list elements.
%
% On success, ioctl/5 returns a 3-tuple:
%
% • Result: an integer equal to the return value of the ioctl
%
% Usually 0 but some ioctls may use the return value as the output
% parameter.
%
% • Bin: the value depends on the type of the input parameter Argp
%
% • cstruct: contains the contents of the memory pointed to by Argp
%
% • integer/binary: an empty binary
%
% == Examples ==
%
% An example of creating a tap device in a net namespace on Linux:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newnet]).
% {ok,8288}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/dev/net/tun", [o_rdwr], 0).
% {ok,6}
% 4> {ok, 0, <<"tap", _/binary>>} = alcove:ioctl(Drv, [Pid], FD, tunsetiff, <<
% 4> % generate a tuntap device name
% 4> 0:(16 * 8),
% 4> % IFF_TAP, IFF_NO_PI
% 4> (16#0002 bor 16#1000):2/native-unsigned-integer-unit:8,
% 4> 0:(14 * 8)
% 4> >>).
% {ok,0,
% <<116,97,112,48,0,0,0,0,0,0,0,0,0,0,0,0,2,16,0,0,0,0,0,0,
% 0,0,...>>}
% '''
ioctl(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
ioctl,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc Convert ioctl constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:ioctl_constant(Drv, [], siocgifaddr).
% 35093
% '''
ioctl_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
ioctl_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert ioctl constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:ioctl_constant(Drv, [], siocgifaddr).
% 35093
% '''
ioctl_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
ioctl_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @private
% @doc Convert iolist to binary
%
% Test conversion of iolists to binary in a control process.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:iolist_to_bin(Drv, [], ["foo", [<<"1">>, <<"2">>, [<<"3">>], ["bar"]]]).
% <<"foo123bar">>
% '''
iolist_to_bin(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
iolist_to_bin,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @private
% @doc Convert iolist to binary
%
% Test conversion of iolists to binary in a control process.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:iolist_to_bin(Drv, [], ["foo", [<<"1">>, <<"2">>, [<<"3">>], ["bar"]]]).
% <<"foo123bar">>
% '''
iolist_to_bin(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
iolist_to_bin,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc jail(2): restrict the current process in a system jail
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 3> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 4> Jail0 = alcove_cstruct:jail(#alcove_jail{
% 4> path = "/rescue",
% 4> hostname = "test0",
% 4> jailname = "jail0"
% 4> }).
% [<<2,0,0,0>>,
% <<0,0,0,0>>,
% {ptr,<<47,114,101,115,99,117,101,0>>},
% {ptr,<<116,101,115,116,48,0>>},
% {ptr,<<106,97,105,108,48,0>>},
% <<0,0,0,0,0,0,0,0>>,
% {ptr,<<>>},
% {ptr,<<>>}]
% 5> {ok, JID0} = alcove:jail(Drv, [Pid], Jail0).
% {ok,21}
% 6> alcove:gethostname(Drv, [Pid]).
% {ok,<<"test0">>}
% '''
jail(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, jail, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc jail(2): restrict the current process in a system jail
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 3> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 4> Jail0 = alcove_cstruct:jail(#alcove_jail{
% 4> path = "/rescue",
% 4> hostname = "test0",
% 4> jailname = "jail0"
% 4> }).
% [<<2,0,0,0>>,
% <<0,0,0,0>>,
% {ptr,<<47,114,101,115,99,117,101,0>>},
% {ptr,<<116,101,115,116,48,0>>},
% {ptr,<<106,97,105,108,48,0>>},
% <<0,0,0,0,0,0,0,0>>,
% {ptr,<<>>},
% {ptr,<<>>}]
% 5> {ok, JID0} = alcove:jail(Drv, [Pid], Jail0).
% {ok,21}
% 6> alcove:gethostname(Drv, [Pid]).
% {ok,<<"test0">>}
% '''
jail(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, jail, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc jail_attach(2): join a jailed process
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 3> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 4> Jail0 = alcove_cstruct:jail(#alcove_jail{
% 4> path = "/rescue",
% 4> hostname = "test0",
% 4> jailname = "jail0"
% 4> }).
% [<<2,0,0,0>>,
% <<0,0,0,0>>,
% {ptr,<<47,114,101,115,99,117,101,0>>},
% {ptr,<<116,101,115,116,48,0>>},
% {ptr,<<106,97,105,108,48,0>>},
% <<0,0,0,0,0,0,0,0>>,
% {ptr,<<>>},
% {ptr,<<>>}]
% 5> {ok, JID0} = alcove:jail(Drv, [Pid], Jail0).
% {ok,21}
% 6> {ok, Pid0} = alcove:fork(Drv, []).
% {ok,44379}
% 7> ok = alcove:jail_attach(Drv, [Pid0], JID0).
% ok
% 8> alcove:gethostname(Drv, [Pid0]).
% {ok,<<"test0">>}
% 9> ok = alcove:jail_remove(Drv, [], JID0).
% ok
% '''
jail_attach(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
jail_attach,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc jail_attach(2): join a jailed process
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 3> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 4> Jail0 = alcove_cstruct:jail(#alcove_jail{
% 4> path = "/rescue",
% 4> hostname = "test0",
% 4> jailname = "jail0"
% 4> }).
% [<<2,0,0,0>>,
% <<0,0,0,0>>,
% {ptr,<<47,114,101,115,99,117,101,0>>},
% {ptr,<<116,101,115,116,48,0>>},
% {ptr,<<106,97,105,108,48,0>>},
% <<0,0,0,0,0,0,0,0>>,
% {ptr,<<>>},
% {ptr,<<>>}]
% 5> {ok, JID0} = alcove:jail(Drv, [Pid], Jail0).
% {ok,21}
% 6> {ok, Pid0} = alcove:fork(Drv, []).
% {ok,44379}
% 7> ok = alcove:jail_attach(Drv, [Pid0], JID0).
% ok
% 8> alcove:gethostname(Drv, [Pid0]).
% {ok,<<"test0">>}
% 9> ok = alcove:jail_remove(Drv, [], JID0).
% ok
% '''
jail_attach(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
jail_attach,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc jail_remove(2): destroy a jailed process
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 3> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 4> Jail0 = alcove_cstruct:jail(#alcove_jail{
% 4> path = "/rescue",
% 4> hostname = "test0",
% 4> jailname = "jail0"
% 4> }).
% [<<2,0,0,0>>,
% <<0,0,0,0>>,
% {ptr,<<47,114,101,115,99,117,101,0>>},
% {ptr,<<116,101,115,116,48,0>>},
% {ptr,<<106,97,105,108,48,0>>},
% <<0,0,0,0,0,0,0,0>>,
% {ptr,<<>>},
% {ptr,<<>>}]
% 5> {ok, JID0} = alcove:jail(Drv, [Pid], Jail0).
% {ok,21}
% 6> {ok, Pid0} = alcove:fork(Drv, []).
% {ok,44379}
% 7> ok = alcove:jail_attach(Drv, [Pid0], JID0).
% ok
% 8> alcove:gethostname(Drv, [Pid0]).
% {ok,<<"test0">>}
% 9> ok = alcove:jail_remove(Drv, [], JID0).
% ok
% '''
jail_remove(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
jail_remove,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc jail_remove(2): destroy a jailed process
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 3> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 4> Jail0 = alcove_cstruct:jail(#alcove_jail{
% 4> path = "/rescue",
% 4> hostname = "test0",
% 4> jailname = "jail0"
% 4> }).
% [<<2,0,0,0>>,
% <<0,0,0,0>>,
% {ptr,<<47,114,101,115,99,117,101,0>>},
% {ptr,<<116,101,115,116,48,0>>},
% {ptr,<<106,97,105,108,48,0>>},
% <<0,0,0,0,0,0,0,0>>,
% {ptr,<<>>},
% {ptr,<<>>}]
% 5> {ok, JID0} = alcove:jail(Drv, [Pid], Jail0).
% {ok,21}
% 6> {ok, Pid0} = alcove:fork(Drv, []).
% {ok,44379}
% 7> ok = alcove:jail_attach(Drv, [Pid0], JID0).
% ok
% 8> alcove:gethostname(Drv, [Pid0]).
% {ok,<<"test0">>}
% 9> ok = alcove:jail_remove(Drv, [], JID0).
% ok
% '''
jail_remove(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
jail_remove,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc kill(2): terminate a process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:kill(Drv, [], 0, 0).
% ok
% 3> alcove:kill(Drv, [], 12345, 0).
% {error,esrch}
% 4> {ok, Pid} = alcove:fork(Drv, []).
% {ok,8288}
% 5> alcove:kill(Drv, [], Pid, 0).
% ok
% 6> alcove:kill(Drv, [], Pid, sigkill).
% ok
% 7> alcove:kill(Drv, [], Pid, 0).
% {error,esrch}
% 8> flush().
% Shell got {alcove_ctl,<0.177.0>,[8288],fdctl_closed}
% Shell got {alcove_event,<0.177.0>,[8288],{termsig,sigkill}}
% '''
kill(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
kill,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc kill(2): terminate a process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:kill(Drv, [], 0, 0).
% ok
% 3> alcove:kill(Drv, [], 12345, 0).
% {error,esrch}
% 4> {ok, Pid} = alcove:fork(Drv, []).
% {ok,8288}
% 5> alcove:kill(Drv, [], Pid, 0).
% ok
% 6> alcove:kill(Drv, [], Pid, sigkill).
% ok
% 7> alcove:kill(Drv, [], Pid, 0).
% {error,esrch}
% 8> flush().
% Shell got {alcove_ctl,<0.177.0>,[8288],fdctl_closed}
% Shell got {alcove_event,<0.177.0>,[8288],{termsig,sigkill}}
% '''
kill(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
kill,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc link(2) : create a hard link
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/alcove-link-test.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 4> alcove:link(Drv, [Pid], "/tmp/alcove-link-test.txt", "/tmp/alcove-link-test.link").
% ok
% '''
link(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
link,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc link(2) : create a hard link
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/tmp/alcove-link-test.txt", [o_wronly, o_creat], 8#644).
% {ok,6}
% 4> alcove:link(Drv, [Pid], "/tmp/alcove-link-test.txt", "/tmp/alcove-link-test.link").
% ok
% '''
link(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
link,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc lseek(2): set file offset for read/write
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> alcove:lseek(Drv, [Pid], FD, 0, 0).
% ok
% '''
lseek(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
lseek,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc lseek(2): set file offset for read/write
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,18820}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> alcove:lseek(Drv, [Pid], FD, 0, 0).
% ok
% '''
lseek(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
lseek,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc mkdir(2): create a directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mkdir(Drv, [], "/tmp/alcove-mkdir-test", 8#755).
% ok
% '''
mkdir(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
mkdir,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc mkdir(2): create a directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mkdir(Drv, [], "/tmp/alcove-mkdir-test", 8#755).
% ok
% '''
mkdir(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
mkdir,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc mkfifo(3): make named pipe file
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mkfifo(Drv, [], "/tmp/alcove-fifo-test", 8#700).
% ok
% '''
mkfifo(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
mkfifo,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc mkfifo(3): make named pipe file
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mkfifo(Drv, [], "/tmp/alcove-fifo-test", 8#700).
% ok
% '''
mkfifo(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
mkfifo,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc mount(2): mount a filesystem, Linux style
%
% The arguments are:
%
% • source
%
% • target
%
% • filesystem type
%
% • flags
%
% • data
%
% An empty list may be used to specify NULL.
%
% For example, filesystems mounted in a Linux mount namespace may be
% visible in the global mount namespace. To avoid this, first remount the
% root filesystem within a mount namespace using the MS_REC|MS_PRIVATE flags:
%
% ```
% {ok, Task} = alcove:clone(Drv, [], [clone_newns]),
% ok = alcove:mount(Drv, [Task], "none", "/", [], [ms_rec, ms_private], []).
% '''
%
% On BSD systems, the `Source' argument is ignored and passed to the system
% mount call as:
%
% ```
% mount(FSType, Target, Flags, Data);
% '''
%
% On Solaris, some mount options are passed in the Options argument as a
% string of comma separated values terminated by a NULL. Other platforms
% ignore the Options parameter.
%
% == Examples ==
%
% An example of bind mounting a directory within a linux mount namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,10059}
% 3> alcove:mount(Drv, [Pid], "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "", "").
% ok
% 4> alcove:umount(Drv, [Pid], "/mnt").
% ok
% '''
mount(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) ->
case alcove_drv:call(Drv,
Pids,
mount,
[Arg1, Arg2, Arg3, Arg4, Arg5, Arg6],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6]);
Reply -> Reply
end.
% @doc mount(2): mount a filesystem, Linux style
%
% The arguments are:
%
% • source
%
% • target
%
% • filesystem type
%
% • flags
%
% • data
%
% An empty list may be used to specify NULL.
%
% For example, filesystems mounted in a Linux mount namespace may be
% visible in the global mount namespace. To avoid this, first remount the
% root filesystem within a mount namespace using the MS_REC|MS_PRIVATE flags:
%
% ```
% {ok, Task} = alcove:clone(Drv, [], [clone_newns]),
% ok = alcove:mount(Drv, [Task], "none", "/", [], [ms_rec, ms_private], []).
% '''
%
% On BSD systems, the `Source' argument is ignored and passed to the system
% mount call as:
%
% ```
% mount(FSType, Target, Flags, Data);
% '''
%
% On Solaris, some mount options are passed in the Options argument as a
% string of comma separated values terminated by a NULL. Other platforms
% ignore the Options parameter.
%
% == Examples ==
%
% An example of bind mounting a directory within a linux mount namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,10059}
% 3> alcove:mount(Drv, [Pid], "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "", "").
% ok
% 4> alcove:umount(Drv, [Pid], "/mnt").
% ok
% '''
mount(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6,
Timeout) ->
case alcove_drv:call(Drv,
Pids,
mount,
[Arg1, Arg2, Arg3, Arg4, Arg5, Arg6],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv,
Pids,
Arg1,
Arg2,
Arg3,
Arg4,
Arg5,
Arg6,
Timeout]);
Reply -> Reply
end.
% @doc Convert flag names to integers
%
% Names are derived from the C macro name with the underscore prefix
% removed. For example, `rdonly' is mapped to MS_RDONLY on Linux and
% MNT_RDONLY on FreeBSD.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mount_constant(Drv, [], rdonly).
% 1
% '''
mount_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
mount_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert flag names to integers
%
% Names are derived from the C macro name with the underscore prefix
% removed. For example, `rdonly' is mapped to MS_RDONLY on Linux and
% MNT_RDONLY on FreeBSD.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mount_constant(Drv, [], rdonly).
% 1
% '''
mount_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
mount_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc open(2): returns a file descriptor associated with a file
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:open(Drv, [], "/tmp/alcove-open-test", [o_wronly,o_creat], 8#644).
% {ok,6}
% '''
open(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
open,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc open(2): returns a file descriptor associated with a file
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:open(Drv, [], "/tmp/alcove-open-test", [o_wronly,o_creat], 8#644).
% {ok,6}
% '''
open(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
open,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc pivot_root(2): change the root mount
%
% Use pivot_root(2) in a Linux mount namespace to change the root
% filesystem.
%
% Warning: using pivot_root(2) in the global namespace may have unexpected
% effects.
%
% To use an arbitrary directory as a mount point:
%
% • mark the mount namespace as private
%
% • create a mount point by bind mounting the new root directory over
% itself
%
% • change the current working directory to the new root directory
%
% • call pivot_root(2) with new and old root set to the current working
% directory
%
% • unmount the current working directory
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.198.0>}
% 2> alcove:mkdir(Drv, [], "/tmp/alcove-root", 8#755).
% ok
% 3> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,29739}
% 4> alcove:mount(Drv, [Pid], "none", "/", [], [ms_rec, ms_private], [], []).
% ok
% 5> alcove:mount(Drv, [Pid], "/tmp/alcove-root", "/tmp/alcove-root", [], [ms_bind], [], []).
% ok
% 6> alcove:chdir(Drv, [Pid], "/tmp/alcove-root").
% ok
% 7> alcove:pivot_root(Drv, [Pid], ".", ".").
% ok
% 8> alcove:umount2(Drv, [Pid], ".", [mnt_detach]).
% ok
% '''
pivot_root(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
pivot_root,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc pivot_root(2): change the root mount
%
% Use pivot_root(2) in a Linux mount namespace to change the root
% filesystem.
%
% Warning: using pivot_root(2) in the global namespace may have unexpected
% effects.
%
% To use an arbitrary directory as a mount point:
%
% • mark the mount namespace as private
%
% • create a mount point by bind mounting the new root directory over
% itself
%
% • change the current working directory to the new root directory
%
% • call pivot_root(2) with new and old root set to the current working
% directory
%
% • unmount the current working directory
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.198.0>}
% 2> alcove:mkdir(Drv, [], "/tmp/alcove-root", 8#755).
% ok
% 3> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,29739}
% 4> alcove:mount(Drv, [Pid], "none", "/", [], [ms_rec, ms_private], [], []).
% ok
% 5> alcove:mount(Drv, [Pid], "/tmp/alcove-root", "/tmp/alcove-root", [], [ms_bind], [], []).
% ok
% 6> alcove:chdir(Drv, [Pid], "/tmp/alcove-root").
% ok
% 7> alcove:pivot_root(Drv, [Pid], ".", ".").
% ok
% 8> alcove:umount2(Drv, [Pid], ".", [mnt_detach]).
% ok
% '''
pivot_root(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
pivot_root,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc pledge(2): restrict system operations
%
% An empty list ([]) specifies promises should not be changed. Warning:
% an empty string ("") is equivalent to an empty list.
%
% To specify no capabilities, use an empty binary: `<<>>>' or `<<"">>'
%
% == Support ==
%
% • OpenBSD
%
% == Examples ==
%
% Fork a control process:
%
% • restricted to stdio, proc and exec capabilities
%
% • unrestricted after calling exec
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,10059}
% 3> alcove:pledge(Drv, [Pid], <<"stdio proc exec">>, []).
% ok
% '''
pledge(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
pledge,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc pledge(2): restrict system operations
%
% An empty list ([]) specifies promises should not be changed. Warning:
% an empty string ("") is equivalent to an empty list.
%
% To specify no capabilities, use an empty binary: `<<>>>' or `<<"">>'
%
% == Support ==
%
% • OpenBSD
%
% == Examples ==
%
% Fork a control process:
%
% • restricted to stdio, proc and exec capabilities
%
% • unrestricted after calling exec
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,10059}
% 3> alcove:pledge(Drv, [Pid], <<"stdio proc exec">>, []).
% ok
% '''
pledge(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
pledge,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc prctl(2): operations on a process
%
% This function can be used to set BPF syscall filters on processes
% (seccomp mode).
%
% A list can be used for prctl operations requiring a C structure as
% an argument. List elements are used to contiguously populate a buffer
% (it is up to the caller to add padding):
%
% • binary(): the element is copied directly into the buffer
%
% On return, the contents of the binary is returned to the caller.
%
% • {ptr, N}: N bytes of memory is allocated and zeroed. The pointer is
% placed in the buffer.
%
% On return, the contents of the memory is returned to the caller.
%
% • {ptr, binary()}
%
% Memory equal to the size of the binary is allocated and initialized
% with the contents of the binary.
%
% On return, the contents of the memory is returned to the caller.
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% To enforce a seccomp filter:
%
% ```
% -module(seccomp).
%
% -include_lib("alcove/include/alcove_seccomp.hrl").
%
% -export([run/2, run/3, filter/3]).
%
% -define(DENY_SYSCALL(Syscall), [
% ?BPF_JUMP(?BPF_JMP + ?BPF_JEQ + ?BPF_K, (Syscall), 0, 1),
% ?BPF_STMT(?BPF_RET + ?BPF_K, ?SECCOMP_RET_KILL)
% ]).
%
% filter(Drv, Pid, Syscall) ->
% Arch = alcove:define(Drv, Pid, alcove:audit_arch()),
% NR = alcove:syscall_constant(Drv, Pid, syscall_constant, Syscall),
%
% [
% ?VALIDATE_ARCHITECTURE(Arch),
% ?EXAMINE_SYSCALL,
% ?DENY_SYSCALL(NR),
% ?BPF_STMT(?BPF_RET + ?BPF_K, ?SECCOMP_RET_ALLOW)
% ].
%
% run(Drv, Pid) ->
% run(Drv, Pid, sys_getcwd).
%
% run(Drv, Pid, Syscall) ->
% Filter = filter(Drv, Pid, Syscall),
%
% {ok, _, _, _, _, _} = alcove:prctl(Drv, Pid, pr_set_no_new_privs, 1, 0, 0, 0),
% Pad = (erlang:system_info({wordsize, external}) - 2) * 8,
%
% Prog = [
% <<(iolist_size(Filter) div 8):2/native-unsigned-integer-unit:8>>,
% <<0:Pad>>,
% {ptr, list_to_binary(Filter)}
% ],
% %% alcove:seccomp(Drv, Pid, seccomp_set_mode_filter, 0, Prog)
% alcove:prctl(Drv, Pid, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).
% '''
%
% @see seccomp/5
prctl(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5) ->
case alcove_drv:call(Drv,
Pids,
prctl,
[Arg1, Arg2, Arg3, Arg4, Arg5],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5]);
Reply -> Reply
end.
% @doc prctl(2): operations on a process
%
% This function can be used to set BPF syscall filters on processes
% (seccomp mode).
%
% A list can be used for prctl operations requiring a C structure as
% an argument. List elements are used to contiguously populate a buffer
% (it is up to the caller to add padding):
%
% • binary(): the element is copied directly into the buffer
%
% On return, the contents of the binary is returned to the caller.
%
% • {ptr, N}: N bytes of memory is allocated and zeroed. The pointer is
% placed in the buffer.
%
% On return, the contents of the memory is returned to the caller.
%
% • {ptr, binary()}
%
% Memory equal to the size of the binary is allocated and initialized
% with the contents of the binary.
%
% On return, the contents of the memory is returned to the caller.
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% To enforce a seccomp filter:
%
% ```
% -module(seccomp).
%
% -include_lib("alcove/include/alcove_seccomp.hrl").
%
% -export([run/2, run/3, filter/3]).
%
% -define(DENY_SYSCALL(Syscall), [
% ?BPF_JUMP(?BPF_JMP + ?BPF_JEQ + ?BPF_K, (Syscall), 0, 1),
% ?BPF_STMT(?BPF_RET + ?BPF_K, ?SECCOMP_RET_KILL)
% ]).
%
% filter(Drv, Pid, Syscall) ->
% Arch = alcove:define(Drv, Pid, alcove:audit_arch()),
% NR = alcove:syscall_constant(Drv, Pid, syscall_constant, Syscall),
%
% [
% ?VALIDATE_ARCHITECTURE(Arch),
% ?EXAMINE_SYSCALL,
% ?DENY_SYSCALL(NR),
% ?BPF_STMT(?BPF_RET + ?BPF_K, ?SECCOMP_RET_ALLOW)
% ].
%
% run(Drv, Pid) ->
% run(Drv, Pid, sys_getcwd).
%
% run(Drv, Pid, Syscall) ->
% Filter = filter(Drv, Pid, Syscall),
%
% {ok, _, _, _, _, _} = alcove:prctl(Drv, Pid, pr_set_no_new_privs, 1, 0, 0, 0),
% Pad = (erlang:system_info({wordsize, external}) - 2) * 8,
%
% Prog = [
% <<(iolist_size(Filter) div 8):2/native-unsigned-integer-unit:8>>,
% <<0:Pad>>,
% {ptr, list_to_binary(Filter)}
% ],
% %% alcove:seccomp(Drv, Pid, seccomp_set_mode_filter, 0, Prog)
% alcove:prctl(Drv, Pid, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).
% '''
%
% @see seccomp/5
prctl(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5,
Timeout) ->
case alcove_drv:call(Drv,
Pids,
prctl,
[Arg1, Arg2, Arg3, Arg4, Arg5],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4, Arg5, Timeout]);
Reply -> Reply
end.
% @doc Convert prctl option names to integers
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:prctl_constant(Drv, [], pr_set_name).
% 15
% '''
prctl_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
prctl_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert prctl option names to integers
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:prctl_constant(Drv, [], pr_set_name).
% 15
% '''
prctl_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
prctl_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc procctl(2): control processes
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Pid, []).
% {ok,44378}
% 3> alcove:procctl(Drv, [Pid], 0, Pid, proc_reap_acquire, []).
% {ok,<<>>,[]}
% 4> alcove:procctl(Drv, [Pid], p_pid, Pid, proc_reap_status, [
% 4> <<0,0,0,0>>, % rs_flags
% 4> <<0,0,0,0>>, % rs_children
% 4> <<0,0,0,0>>, % rs_descendants
% 4> <<0,0,0,0>>, % rs_reaper
% 4> <<0,0,0,0>> % rs_pid
% 4> ]).
% {ok,<<1,0,0,0,0,0,0,0,0,0,0,0,118,173,0,0,255,255,255,255>>,
% [<<1,0,0,0>>,
% <<0,0,0,0>>,
% <<0,0,0,0>>,
% <<118,173,0,0>>,
% <<"\377\377\377\377">>]}
% '''
procctl(Drv, Pids, Arg1, Arg2, Arg3, Arg4) ->
case alcove_drv:call(Drv,
Pids,
procctl,
[Arg1, Arg2, Arg3, Arg4],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4]);
Reply -> Reply
end.
% @doc procctl(2): control processes
%
% == Support ==
%
% • FreeBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Pid, []).
% {ok,44378}
% 3> alcove:procctl(Drv, [Pid], 0, Pid, proc_reap_acquire, []).
% {ok,<<>>,[]}
% 4> alcove:procctl(Drv, [Pid], p_pid, Pid, proc_reap_status, [
% 4> <<0,0,0,0>>, % rs_flags
% 4> <<0,0,0,0>>, % rs_children
% 4> <<0,0,0,0>>, % rs_descendants
% 4> <<0,0,0,0>>, % rs_reaper
% 4> <<0,0,0,0>> % rs_pid
% 4> ]).
% {ok,<<1,0,0,0,0,0,0,0,0,0,0,0,118,173,0,0,255,255,255,255>>,
% [<<1,0,0,0>>,
% <<0,0,0,0>>,
% <<0,0,0,0>>,
% <<118,173,0,0>>,
% <<"\377\377\377\377">>]}
% '''
procctl(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Timeout) ->
case alcove_drv:call(Drv,
Pids,
procctl,
[Arg1, Arg2, Arg3, Arg4],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4, Timeout]);
Reply -> Reply
end.
% @doc ptrace(2): process trace
%
% == Examples ==
%
% ```
% -module(ptrace).
%
% -export([run/0]).
%
% run() ->
% {ok, Drv} = alcove_drv:start_link(),
% {ok, Pid1} = alcove:fork(Drv, []),
%
% {ok, Pid2} = alcove:fork(Drv, [Pid1]),
%
% % disable the alcove event loop: child process must be managed by
% % the caller
% {ok, sig_dfl} = alcove:sigaction(Drv, [Pid1], sigchld, sig_info),
%
% % enable ptracing in the child process and exec() a command
% {ok, 0, <<>>, <<>>} = alcove:ptrace(
% Drv,
% [Pid1, Pid2],
% ptrace_traceme,
% 0,
% 0,
% 0
% ),
% ok = alcove:execvp(Drv, [Pid1, Pid2], "cat", ["cat"]),
%
% % the parent is notified
% {signal, sigchld, _} = alcove:event(Drv, [Pid1], 5000),
% {ok, Pid2, _, [{stopsig, sigtrap}]} = alcove:waitpid(
% Drv,
% [Pid1],
% -1,
% [wnohang]
% ),
%
% % should be no other events
% {ok, 0, 0, []} = alcove:waitpid(Drv, [Pid1], -1, [wnohang]),
%
% % allow the process to continue
% {ok, 0, <<>>, <<>>} = alcove:ptrace(Drv, [Pid1], ptrace_cont, Pid2, 0, 0),
%
% ok = alcove:stdin(Drv, [Pid1, Pid2], "test\n"),
%
% ok =
% receive
% {alcove_stdout, Drv, [Pid1, Pid2], <<"test\n">>} ->
% ok
% after 5000 -> timeout
% end,
%
% % Send a SIGTERM and re-write it to a harmless SIGWINCH
% ok = alcove:kill(Drv, [Pid1], Pid2, sigterm),
% {signal, sigchld, _} = alcove:event(Drv, [Pid1], 5000),
% {ok, Pid2, _, [{stopsig, sigterm}]} = alcove:waitpid(
% Drv,
% [Pid1],
% -1,
% [wnohang]
% ),
%
% {ok, 0, <<>>, <<>>} = alcove:ptrace(
% Drv,
% [Pid1],
% ptrace_cont,
% Pid2,
% 0,
% 28
% ),
%
% % Convert a SIGWINCH to SIGTERM
% ok = alcove:kill(Drv, [Pid1], Pid2, sigwinch),
% {signal, sigchld, _} = alcove:event(Drv, [Pid1], 5000),
% {ok, 0, <<>>, <<>>} = alcove:ptrace(
% Drv,
% [Pid1],
% ptrace_cont,
% Pid2,
% 0,
% 15
% ),
% {ok, Pid2, _, [{termsig, sigterm}]} = alcove:waitpid(
% Drv,
% [Pid1],
% -1,
% []
% ).
% '''
ptrace(Drv, Pids, Arg1, Arg2, Arg3, Arg4) ->
case alcove_drv:call(Drv,
Pids,
ptrace,
[Arg1, Arg2, Arg3, Arg4],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4]);
Reply -> Reply
end.
% @doc ptrace(2): process trace
%
% == Examples ==
%
% ```
% -module(ptrace).
%
% -export([run/0]).
%
% run() ->
% {ok, Drv} = alcove_drv:start_link(),
% {ok, Pid1} = alcove:fork(Drv, []),
%
% {ok, Pid2} = alcove:fork(Drv, [Pid1]),
%
% % disable the alcove event loop: child process must be managed by
% % the caller
% {ok, sig_dfl} = alcove:sigaction(Drv, [Pid1], sigchld, sig_info),
%
% % enable ptracing in the child process and exec() a command
% {ok, 0, <<>>, <<>>} = alcove:ptrace(
% Drv,
% [Pid1, Pid2],
% ptrace_traceme,
% 0,
% 0,
% 0
% ),
% ok = alcove:execvp(Drv, [Pid1, Pid2], "cat", ["cat"]),
%
% % the parent is notified
% {signal, sigchld, _} = alcove:event(Drv, [Pid1], 5000),
% {ok, Pid2, _, [{stopsig, sigtrap}]} = alcove:waitpid(
% Drv,
% [Pid1],
% -1,
% [wnohang]
% ),
%
% % should be no other events
% {ok, 0, 0, []} = alcove:waitpid(Drv, [Pid1], -1, [wnohang]),
%
% % allow the process to continue
% {ok, 0, <<>>, <<>>} = alcove:ptrace(Drv, [Pid1], ptrace_cont, Pid2, 0, 0),
%
% ok = alcove:stdin(Drv, [Pid1, Pid2], "test\n"),
%
% ok =
% receive
% {alcove_stdout, Drv, [Pid1, Pid2], <<"test\n">>} ->
% ok
% after 5000 -> timeout
% end,
%
% % Send a SIGTERM and re-write it to a harmless SIGWINCH
% ok = alcove:kill(Drv, [Pid1], Pid2, sigterm),
% {signal, sigchld, _} = alcove:event(Drv, [Pid1], 5000),
% {ok, Pid2, _, [{stopsig, sigterm}]} = alcove:waitpid(
% Drv,
% [Pid1],
% -1,
% [wnohang]
% ),
%
% {ok, 0, <<>>, <<>>} = alcove:ptrace(
% Drv,
% [Pid1],
% ptrace_cont,
% Pid2,
% 0,
% 28
% ),
%
% % Convert a SIGWINCH to SIGTERM
% ok = alcove:kill(Drv, [Pid1], Pid2, sigwinch),
% {signal, sigchld, _} = alcove:event(Drv, [Pid1], 5000),
% {ok, 0, <<>>, <<>>} = alcove:ptrace(
% Drv,
% [Pid1],
% ptrace_cont,
% Pid2,
% 0,
% 15
% ),
% {ok, Pid2, _, [{termsig, sigterm}]} = alcove:waitpid(
% Drv,
% [Pid1],
% -1,
% []
% ).
% '''
ptrace(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Timeout) ->
case alcove_drv:call(Drv,
Pids,
ptrace,
[Arg1, Arg2, Arg3, Arg4],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4, Timeout]);
Reply -> Reply
end.
% @doc Convert ptrace constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:ptrace_constant(Drv, [], ptrace_traceme).
% 0
% '''
ptrace_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
ptrace_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert ptrace constant to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:ptrace_constant(Drv, [], ptrace_traceme).
% 0
% '''
ptrace_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
ptrace_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc read(2): read bytes from a file descriptor
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> alcove:read(Drv, [Pid], FD, 64).
% {ok,<<"# $FreeBSD$\n#\nroot:*:0:0:Charlie &:/root:/bin/csh\ntoor:*:0:0:Bou">>}
% '''
read(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
read,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc read(2): read bytes from a file descriptor
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,75710}
% 3> {ok, FD} = alcove:open(Drv, [Pid], "/etc/passwd", [o_rdonly], 0).
% {ok,6}
% 4> alcove:read(Drv, [Pid], FD, 64).
% {ok,<<"# $FreeBSD$\n#\nroot:*:0:0:Charlie &:/root:/bin/csh\ntoor:*:0:0:Bou">>}
% '''
read(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
read,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc readdir(3): retrieve list of objects in a directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> alcove:readdir(Drv, [], "/dev/pts").
% {ok,[<<".">>,<<"..">>,<<"50">>,<<"49">>,<<"45">>,<<"48">>,
% <<"47">>,<<"46">>,<<"44">>,<<"43">>,<<"42">>,<<"41">>,
% <<"40">>,<<"39">>,<<"38">>,<<"37">>,<<"36">>,<<"35">>,
% <<"34">>,<<"33">>,<<"32">>,<<"31">>,<<"30">>,<<"29">>,
% <<"28">>,<<"27">>,<<...>>|...]}
% '''
readdir(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
readdir,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc readdir(3): retrieve list of objects in a directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.209.0>}
% 2> alcove:readdir(Drv, [], "/dev/pts").
% {ok,[<<".">>,<<"..">>,<<"50">>,<<"49">>,<<"45">>,<<"48">>,
% <<"47">>,<<"46">>,<<"44">>,<<"43">>,<<"42">>,<<"41">>,
% <<"40">>,<<"39">>,<<"38">>,<<"37">>,<<"36">>,<<"35">>,
% <<"34">>,<<"33">>,<<"32">>,<<"31">>,<<"30">>,<<"29">>,
% <<"28">>,<<"27">>,<<...>>|...]}
% '''
readdir(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
readdir,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc Convert an RLIMIT_* flag to an integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:rlimit_constant(Drv, [], rlimit_nofile).
% 7
% '''
rlimit_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
rlimit_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert an RLIMIT_* flag to an integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:rlimit_constant(Drv, [], rlimit_nofile).
% 7
% '''
rlimit_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
rlimit_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc rmdir(2): delete a directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mkdir(Drv, [], "/tmp/alcove-rmdir-test", 8#755).
% ok
% 3> alcove:rmdir(Drv, [], "/tmp/alcove-rmdir-test").
% ok
% '''
rmdir(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv, Pids, rmdir, [Arg1], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc rmdir(2): delete a directory
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:mkdir(Drv, [], "/tmp/alcove-rmdir-test", 8#755).
% ok
% 3> alcove:rmdir(Drv, [], "/tmp/alcove-rmdir-test").
% ok
% '''
rmdir(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, rmdir, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc seccomp(2): restrict system operations
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% '''
% %% Equivalent to:
% %% alcove:prctl(Drv, Pid, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0)
% alcove:seccomp(Drv, Pid, seccomp_set_mode_filter, 0, Prog)
% '''
%
% @see prctl/7
seccomp(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
seccomp,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc seccomp(2): restrict system operations
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% '''
% %% Equivalent to:
% %% alcove:prctl(Drv, Pid, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0)
% alcove:seccomp(Drv, Pid, seccomp_set_mode_filter, 0, Prog)
% '''
%
% @see prctl/7
seccomp(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
seccomp,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc Convert seccomp option name to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:seccomp_constant(Drv, [], seccomp_set_mode_strict).
% 0
% '''
seccomp_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
seccomp_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert seccomp option name to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:seccomp_constant(Drv, [], seccomp_set_mode_strict).
% 0
% '''
seccomp_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
seccomp_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc select(2): poll a list of file descriptor for events
%
% select/6 will block until an event occurs on a file descriptor, a timeout
% is reached or interrupted by a signal.
%
% The Timeout value may be:
%
% • an empty list ([]): causes select to block indefinitely (no timeout)
%
% • an alcove_timeval record
%
% An alcove_timeval record contains these fields:
%
% • sec : number of seconds to wait
%
% • usec : number of microseconds to wait
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, FD} = alcove:open(Drv, [], "/dev/null", [o_rdwr], 0).
% {ok,6}
% 3> alcove:select(Drv, [], [FD], [FD], [FD], []).
% {ok,[6],[6],[]}
% 4> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 5> alcove:select(Drv, [], [FD], [FD], [FD], #alcove_timeval{sec = 1, usec = 1}).
% {ok,[6],[6],[]}
% '''
select(Drv, Pids, Arg1, Arg2, Arg3, Arg4) ->
case alcove_drv:call(Drv,
Pids,
select,
[Arg1, Arg2, Arg3, Arg4],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4]);
Reply -> Reply
end.
% @doc select(2): poll a list of file descriptor for events
%
% select/6 will block until an event occurs on a file descriptor, a timeout
% is reached or interrupted by a signal.
%
% The Timeout value may be:
%
% • an empty list ([]): causes select to block indefinitely (no timeout)
%
% • an alcove_timeval record
%
% An alcove_timeval record contains these fields:
%
% • sec : number of seconds to wait
%
% • usec : number of microseconds to wait
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, FD} = alcove:open(Drv, [], "/dev/null", [o_rdwr], 0).
% {ok,6}
% 3> alcove:select(Drv, [], [FD], [FD], [FD], []).
% {ok,[6],[6],[]}
% 4> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 5> alcove:select(Drv, [], [FD], [FD], [FD], #alcove_timeval{sec = 1, usec = 1}).
% {ok,[6],[6],[]}
% '''
select(Drv, Pids, Arg1, Arg2, Arg3, Arg4, Timeout) ->
case alcove_drv:call(Drv,
Pids,
select,
[Arg1, Arg2, Arg3, Arg4],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Arg4, Timeout]);
Reply -> Reply
end.
% @doc Set options for child process of alcove control process
%
% `flowcontrol' enables rate limiting of the stdout and stderr of a child
% process. stdin is not rate limited (default: -1 (disabled))
%
% • 0: stdout/stderr for process is not read
%
% • 1-2147483646: read this many messages from the process
%
% • -1: disable flow control
%
% NOTE: the limit applies to stdout and stderr. If the limit is set to 1,
% it is possible to get:
%
% • 1 message from stdout
%
% • 1 message from stderr
%
% • 1 message from stdout and stderr
%
% `signaloneof' delivers a signal to any subprocesses when the alcove
% control process shuts down (default: 15 (SIGTERM))
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,24440}
% 3> alcove:setcpid(Drv, [], Pid, flowcontrol, 0).
% true
% 4> alcove:getcpid(Drv, [], Pid, flowcontrol).
% 0
% '''
setcpid(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
setcpid,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc Set options for child process of alcove control process
%
% `flowcontrol' enables rate limiting of the stdout and stderr of a child
% process. stdin is not rate limited (default: -1 (disabled))
%
% • 0: stdout/stderr for process is not read
%
% • 1-2147483646: read this many messages from the process
%
% • -1: disable flow control
%
% NOTE: the limit applies to stdout and stderr. If the limit is set to 1,
% it is possible to get:
%
% • 1 message from stdout
%
% • 1 message from stderr
%
% • 1 message from stdout and stderr
%
% `signaloneof' delivers a signal to any subprocesses when the alcove
% control process shuts down (default: 15 (SIGTERM))
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,24440}
% 3> alcove:setcpid(Drv, [], Pid, flowcontrol, 0).
% true
% 4> alcove:getcpid(Drv, [], Pid, flowcontrol).
% 0
% '''
setcpid(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setcpid,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc setenv(3): set an environment variable
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:setenv(Drv, [], "ALCOVE_TEST", "foo", 0).
% ok
% 3> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"foo">>
% 4> alcove:setenv(Drv, [], "ALCOVE_TEST", "bar", 0).
% ok
% 5> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"foo">>
% 6> alcove:setenv(Drv, [], "ALCOVE_TEST", "bar", 1).
% ok
% 7> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"bar">>
% '''
setenv(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
setenv,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc setenv(3): set an environment variable
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:setenv(Drv, [], "ALCOVE_TEST", "foo", 0).
% ok
% 3> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"foo">>
% 4> alcove:setenv(Drv, [], "ALCOVE_TEST", "bar", 0).
% ok
% 5> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"foo">>
% 6> alcove:setenv(Drv, [], "ALCOVE_TEST", "bar", 1).
% ok
% 7> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"bar">>
% '''
setenv(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setenv,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc setgid(2): set the GID of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 72> alcove:setgid(Drv, [Pid], 123).
% ok
% 73> alcove:getgid(Drv, [Pid]).
% 123
% '''
setgid(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
setgid,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc setgid(2): set the GID of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 72> alcove:setgid(Drv, [Pid], 123).
% ok
% 73> alcove:getgid(Drv, [Pid]).
% 123
% '''
setgid(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, setgid, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc setgroups(2): set the supplementary groups of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 75> alcove:setgroups(Drv, [Pid], []).
% ok
% 76> alcove:getgroups(Drv, [Pid]).
% {ok,[]}
% '''
setgroups(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
setgroups,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc setgroups(2): set the supplementary groups of the process
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 75> alcove:setgroups(Drv, [Pid], []).
% ok
% 76> alcove:getgroups(Drv, [Pid]).
% {ok,[]}
% '''
setgroups(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setgroups,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc sethostname(2): set the system hostname
%
% This function is probably only useful if running in a uts namespace or
% a jail.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newuts]).
% {ok,44378}
% 3> alcove:sethostname(Drv, [Pid], "test").
% ok
% 4> alcove:gethostname(Drv, []).
% {ok,<<"host1">>}
% 5> alcove:gethostname(Drv, [Pid]).
% {ok,<<"test">>}
% '''
sethostname(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
sethostname,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc sethostname(2): set the system hostname
%
% This function is probably only useful if running in a uts namespace or
% a jail.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newuts]).
% {ok,44378}
% 3> alcove:sethostname(Drv, [Pid], "test").
% ok
% 4> alcove:gethostname(Drv, []).
% {ok,<<"host1">>}
% 5> alcove:gethostname(Drv, [Pid]).
% {ok,<<"test">>}
% '''
sethostname(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
sethostname,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc setns(2): attach to a namespace
%
% A process namespace is represented as a path in the /proc filesystem. The
% path is `/proc/<pid>/ns/<ns>', where:
%
% • pid: the system PID
%
% • ns: a file representing the namespace
%
% The available namespaces is dependent on the kernel version. You can
% see which are supported by running:
%
% ```
% ls -al /proc/$$/ns
% '''
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% Attach a process to an existing network namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid1} = alcove:clone(Drv, [], [clone_newnet]).
% {ok,27125}
% 3> {ok, Pid2} = alcove:fork(Drv, []).
% {ok,27126}
% % Move Pid2 into the Pid1 network namespace
% 4> {ok, FD} = alcove:open(Drv, [Pid2], ["/proc/", integer_to_list(Pid1), "/ns/net"], [o_rdonly], 0).
% {ok,8}
% 5> alcove:setns(Drv, [Pid2], FD, 0).
% ok
% 6> alcove:close(Drv, [Pid2], FD).
% '''
setns(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
setns,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc setns(2): attach to a namespace
%
% A process namespace is represented as a path in the /proc filesystem. The
% path is `/proc/<pid>/ns/<ns>', where:
%
% • pid: the system PID
%
% • ns: a file representing the namespace
%
% The available namespaces is dependent on the kernel version. You can
% see which are supported by running:
%
% ```
% ls -al /proc/$$/ns
% '''
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% Attach a process to an existing network namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid1} = alcove:clone(Drv, [], [clone_newnet]).
% {ok,27125}
% 3> {ok, Pid2} = alcove:fork(Drv, []).
% {ok,27126}
% % Move Pid2 into the Pid1 network namespace
% 4> {ok, FD} = alcove:open(Drv, [Pid2], ["/proc/", integer_to_list(Pid1), "/ns/net"], [o_rdonly], 0).
% {ok,8}
% 5> alcove:setns(Drv, [Pid2], FD, 0).
% ok
% 6> alcove:close(Drv, [Pid2], FD).
% '''
setns(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setns,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc Set port options
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:setopt(Drv, [], maxforkdepth, 128).
% true
% '''
%
% @see getopt/3
setopt(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
setopt,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc Set port options
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:setopt(Drv, [], maxforkdepth, 128).
% true
% '''
%
% @see getopt/3
setopt(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setopt,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc setpgid(2): set process group
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28210}
% 3> alcove:setpgid(Drv, [Pid], 0, 0).
% ok
% '''
setpgid(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
setpgid,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc setpgid(2): set process group
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28210}
% 3> alcove:setpgid(Drv, [Pid], 0, 0).
% ok
% '''
setpgid(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setpgid,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc setpriority(2): set scheduling priority of process, process group or user
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28210}
% 3> alcove:setpriority(Drv, [Pid], prio_process, 0, 10).
% ok
% 4> alcove:getpriority(Drv, [Pid], prio_process, 0).
% {ok,10}
% '''
setpriority(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
setpriority,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc setpriority(2): set scheduling priority of process, process group or user
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28210}
% 3> alcove:setpriority(Drv, [Pid], prio_process, 0, 10).
% ok
% 4> alcove:getpriority(Drv, [Pid], prio_process, 0).
% {ok,10}
% '''
setpriority(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setpriority,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc setproctitle(3): set the process title
%
% Overwrites arg0.
%
% On Linux, prctl/6,7 can be used to set the command name:
%
% ```
% {ok,Fork} = alcove:fork(Drv, []),
% alcove:prctl(Drv, [Fork], pr_set_name, <<"pseudonym">>, 0,0,0).
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28210}
% 3> alcove:setproctitle(Drv, [Pid], "new process name").
% ok
% '''
setproctitle(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
setproctitle,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc setproctitle(3): set the process title
%
% Overwrites arg0.
%
% On Linux, prctl/6,7 can be used to set the command name:
%
% ```
% {ok,Fork} = alcove:fork(Drv, []),
% alcove:prctl(Drv, [Fork], pr_set_name, <<"pseudonym">>, 0,0,0).
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28210}
% 3> alcove:setproctitle(Drv, [Pid], "new process name").
% ok
% '''
setproctitle(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setproctitle,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc setresgid(2): set real, effective and saved group ID
%
% == Support ==
%
% • Linux
%
% • FreeBSD
%
% • OpenBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:setresgid(Drv, [Pid], 123, 123, 123).
% ok
% '''
setresgid(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
setresgid,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc setresgid(2): set real, effective and saved group ID
%
% == Support ==
%
% • Linux
%
% • FreeBSD
%
% • OpenBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:setresgid(Drv, [Pid], 123, 123, 123).
% ok
% '''
setresgid(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setresgid,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc setresuid(2): set real, effective and saved user ID
%
% == Support ==
%
% • Linux
%
% • FreeBSD
%
% • OpenBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:setresuid(Drv, [Pid], 123, 123, 123).
% ok
% '''
setresuid(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
setresuid,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc setresuid(2): set real, effective and saved user ID
%
% == Support ==
%
% • Linux
%
% • FreeBSD
%
% • OpenBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:setresuid(Drv, [Pid], 123, 123, 123).
% ok
% '''
setresuid(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setresuid,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc setrlimit(2): set a resource limit
%
% Note on `rlimit_nofile':
%
% The control process requires a fixed number of file descriptors for
% each subprocess. Reducing the number of file descriptors will reduce
% the limit on child processes.
%
% If the file descriptor limit is below the number of file descriptors
% currently used, setrlimit/4,5 will return `{error, einval}'.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 3> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 4> alcove:getrlimit(Drv, [Pid], rlimit_nofile).
% {ok,#alcove_rlimit{cur = 1024,max = 1048576}}
% 5> alcove:setrlimit(Drv, [Pid], rlimit_nofile, #alcove_rlimit{cur = 64, max = 64}).
% ok
% 6> alcove:getrlimit(Drv, [Pid], rlimit_nofile).
% {ok,#alcove_rlimit{cur = 64,max = 64}}
% '''
setrlimit(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
setrlimit,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc setrlimit(2): set a resource limit
%
% Note on `rlimit_nofile':
%
% The control process requires a fixed number of file descriptors for
% each subprocess. Reducing the number of file descriptors will reduce
% the limit on child processes.
%
% If the file descriptor limit is below the number of file descriptors
% currently used, setrlimit/4,5 will return `{error, einval}'.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 3> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 4> alcove:getrlimit(Drv, [Pid], rlimit_nofile).
% {ok,#alcove_rlimit{cur = 1024,max = 1048576}}
% 5> alcove:setrlimit(Drv, [Pid], rlimit_nofile, #alcove_rlimit{cur = 64, max = 64}).
% ok
% 6> alcove:getrlimit(Drv, [Pid], rlimit_nofile).
% {ok,#alcove_rlimit{cur = 64,max = 64}}
% '''
setrlimit(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
setrlimit,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc setsid(2): create a new session
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:setsid(Drv, [Pid]).
% {ok,28493}
% '''
setsid(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, setsid, [], infinity) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc setsid(2): create a new session
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:setsid(Drv, [Pid]).
% {ok,28493}
% '''
setsid(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, setsid, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc setuid(2): change UID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 72> alcove:setuid(Drv, [Pid], 123).
% ok
% 73> alcove:getuid(Drv, [Pid]).
% 123
% '''
%
% @see setresuid/5
setuid(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
setuid,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc setuid(2): change UID
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.208.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,44378}
% 72> alcove:setuid(Drv, [Pid], 123).
% ok
% 73> alcove:getuid(Drv, [Pid]).
% 123
% '''
%
% @see setresuid/5
setuid(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, setuid, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc sigaction(2): set process behaviour for signals
%
% • sig_dfl
%
% Uses the default behaviour for the signal
%
% • sig_ign
%
% Ignores the signal
%
% • sig_info
%
% Catches the signal and sends the controlling Erlang process an event:
%
% ```
% {signal, atom(), Info}
% '''
%
% Info is a binary containing the siginfo_t structure. See sigaction(2)
% for details.
%
% • []
%
% Returns the current handler for the signal.
%
% Multiple caught signals of the same type may be reported as one event.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 3> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 4> alcove:kill(Drv, [], Pid, sigterm).
% ok
% 5> flush().
% Shell got {alcove_event,<0.177.0>,
% [28493],
% {signal,sigterm,
% <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,111,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0>>}}
% ok
% 6> alcove:sigaction(Drv, [Pid], sigterm, sig_ign).
% {ok,sig_info}
% 7> alcove:kill(Drv, [], Pid, sigterm).
% ok
% 8> flush().
% ok
% 9> alcove:sigaction(Drv, [Pid], sigterm, sig_info).
% {ok,sig_ign}
% 10> alcove:kill(Drv, [], Pid, sigterm).
% ok
% 11> flush().
% Shell got {alcove_event,<0.177.0>,
% [28493],
% {signal,sigterm,
% <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,111,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0>>}}
% ok
% '''
sigaction(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
sigaction,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc sigaction(2): set process behaviour for signals
%
% • sig_dfl
%
% Uses the default behaviour for the signal
%
% • sig_ign
%
% Ignores the signal
%
% • sig_info
%
% Catches the signal and sends the controlling Erlang process an event:
%
% ```
% {signal, atom(), Info}
% '''
%
% Info is a binary containing the siginfo_t structure. See sigaction(2)
% for details.
%
% • []
%
% Returns the current handler for the signal.
%
% Multiple caught signals of the same type may be reported as one event.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> rr(alcove).
% [alcove_jail,alcove_pid,alcove_rlimit,alcove_timeval]
% 3> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 4> alcove:kill(Drv, [], Pid, sigterm).
% ok
% 5> flush().
% Shell got {alcove_event,<0.177.0>,
% [28493],
% {signal,sigterm,
% <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,111,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0>>}}
% ok
% 6> alcove:sigaction(Drv, [Pid], sigterm, sig_ign).
% {ok,sig_info}
% 7> alcove:kill(Drv, [], Pid, sigterm).
% ok
% 8> flush().
% ok
% 9> alcove:sigaction(Drv, [Pid], sigterm, sig_info).
% {ok,sig_ign}
% 10> alcove:kill(Drv, [], Pid, sigterm).
% ok
% 11> flush().
% Shell got {alcove_event,<0.177.0>,
% [28493],
% {signal,sigterm,
% <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,111,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 0,0,0,0>>}}
% ok
% '''
sigaction(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
sigaction,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc Convert signal names to integers
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:signal_constant(Drv, [], sighup).
% 1
% '''
signal_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
signal_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert signal names to integers
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:signal_constant(Drv, [], sighup).
% 1
% '''
signal_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
signal_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc socket(2): returns a file descriptor for a communication endpoint
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Socket} = alcove:socket(Drv, [], af_inet, sock_stream, 0).
% {ok,6}
% 3> alcove:close(Drv, [], Socket).
% ok
% '''
socket(Drv, Pids, Arg1, Arg2, Arg3) ->
case alcove_drv:call(Drv,
Pids,
socket,
[Arg1, Arg2, Arg3],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Arg3]);
Reply -> Reply
end.
% @doc socket(2): returns a file descriptor for a communication endpoint
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Socket} = alcove:socket(Drv, [], af_inet, sock_stream, 0).
% {ok,6}
% 3> alcove:close(Drv, [], Socket).
% ok
% '''
socket(Drv, Pids, Arg1, Arg2, Arg3, Timeout) ->
case alcove_drv:call(Drv,
Pids,
socket,
[Arg1, Arg2, Arg3],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error,
[Drv, Pids, Arg1, Arg2, Arg3, Timeout]);
Reply -> Reply
end.
% @doc symlink(2): create a symbolic link
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:symlink(Drv, [], "/etc/hosts", "/tmp/hosts.tmp").
% ok
% '''
symlink(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
symlink,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc symlink(2): create a symbolic link
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:symlink(Drv, [], "/etc/hosts", "/tmp/hosts.tmp").
% ok
% '''
symlink(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
symlink,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc Convert syscall name to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:syscall_constant(Drv, [], sys_exit).
% 60
% '''
syscall_constant(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
syscall_constant,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc Convert syscall name to integer
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:syscall_constant(Drv, [], sys_exit).
% 60
% '''
syscall_constant(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
syscall_constant,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc umount(2): unmount a filesystem
%
% On BSD systems, calls unmount(2).
%
% == Examples ==
%
% An example of bind mounting a directory within a linux mount namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,10059}
% 3> alcove:mount(Drv, [Pid], "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "", "").
% ok
% 4> alcove:umount(Drv, [Pid], "/mnt").
% ok
% '''
umount(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
umount,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc umount(2): unmount a filesystem
%
% On BSD systems, calls unmount(2).
%
% == Examples ==
%
% An example of bind mounting a directory within a linux mount namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,10059}
% 3> alcove:mount(Drv, [Pid], "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "", "").
% ok
% 4> alcove:umount(Drv, [Pid], "/mnt").
% ok
% '''
umount(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, umount, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc umount2(2): unmount filesystem with flags
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% An example of bind mounting a directory within a linux mount namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,10059}
% 3> alcove:mount(Drv, [Pid], "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "", "").
% ok
% 4> alcove:umount2(Drv, [Pid], "/mnt", [mnt_detach]).
% ok
% '''
umount2(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
umount2,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc umount2(2): unmount filesystem with flags
%
% == Support ==
%
% • Linux
%
% == Examples ==
%
% An example of bind mounting a directory within a linux mount namespace:
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:clone(Drv, [], [clone_newns]).
% {ok,10059}
% 3> alcove:mount(Drv, [Pid], "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "", "").
% ok
% 4> alcove:umount2(Drv, [Pid], "/mnt", [mnt_detach]).
% ok
% '''
umount2(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
umount2,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc unlink(2): delete a name from the filesystem
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:open(Drv, [], "/tmp/alcove-open-test", [o_wronly,o_creat], 8#644).
% {ok,6}
% 3> alcove:unlink(Drv, [], "/tmp/alcove-open-test").
% ok
% '''
unlink(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
unlink,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc unlink(2): delete a name from the filesystem
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:open(Drv, [], "/tmp/alcove-open-test", [o_wronly,o_creat], 8#644).
% {ok,6}
% 3> alcove:unlink(Drv, [], "/tmp/alcove-open-test").
% ok
% '''
unlink(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv, Pids, unlink, [Arg1], Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc unsetenv(3): remove an environment variable
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:setenv(Drv, [], "ALCOVE_TEST", "foo", 0).
% ok
% 3> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"foo">>
% 4> alcove:unsetenv(Drv, [], "ALCOVE_TEST").
% ok
% 5> alcove:getenv(Drv, [], "ALCOVE_TEST").
% false
% '''
unsetenv(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
unsetenv,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc unsetenv(3): remove an environment variable
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:setenv(Drv, [], "ALCOVE_TEST", "foo", 0).
% ok
% 3> alcove:getenv(Drv, [], "ALCOVE_TEST").
% <<"foo">>
% 4> alcove:unsetenv(Drv, [], "ALCOVE_TEST").
% ok
% 5> alcove:getenv(Drv, [], "ALCOVE_TEST").
% false
% '''
unsetenv(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
unsetenv,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc unshare(2): create a new namespace in the current process
%
% Make a new namespace without calling clone(2):
%
% ```
% ok = alcove:unshare(Drv, [], [clone_newnet]).
% % The port is now running in a namespace without network access.
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:unshare(Drv, [Pid], [clone_newuts]).
% ok
% 4> alcove:sethostname(Drv, [Pid], "unshare").
% ok
% 5> alcove:gethostname(Drv, [Pid]).
% {ok,<<"unshare">>}
% 6> alcove:gethostname(Drv, []).
% {ok,<<"host1">>}
% '''
unshare(Drv, Pids, Arg1) ->
case alcove_drv:call(Drv,
Pids,
unshare,
[Arg1],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1]);
Reply -> Reply
end.
% @doc unshare(2): create a new namespace in the current process
%
% Make a new namespace without calling clone(2):
%
% ```
% ok = alcove:unshare(Drv, [], [clone_newnet]).
% % The port is now running in a namespace without network access.
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start([{exec, "sudo -n"}]).
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28493}
% 3> alcove:unshare(Drv, [Pid], [clone_newuts]).
% ok
% 4> alcove:sethostname(Drv, [Pid], "unshare").
% ok
% 5> alcove:gethostname(Drv, [Pid]).
% {ok,<<"unshare">>}
% 6> alcove:gethostname(Drv, []).
% {ok,<<"host1">>}
% '''
unshare(Drv, Pids, Arg1, Timeout) ->
case alcove_drv:call(Drv,
Pids,
unshare,
[Arg1],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Timeout]);
Reply -> Reply
end.
% @doc unveil(2): restrict filesystem view
%
% To disable unveil calls, use an empty list ([]) or, equivalently, an
% empty string ("").
%
% ```
% alcove:unveil(Drv, [Task], <<"/etc">>, <<"r">>),
% alcove:unveil(Drv, [Task], [], []).
% '''
%
% == Support ==
%
% • OpenBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28978}
% 3> alcove:unveil(Drv, [Pid], <<"/etc">>, <<"r">>).
% ok
% 4> alcove:unveil(Drv, [Pid], [], []).
% ok
% 5> alcove:readdir(Drv, [Pid], "/etc").
% {ok,[<<".">>,<<"..">>,<<"acme">>,<<"amd">>,<<"authpf">>,
% <<"daily">>,<<"disktab">>,<<"examples">>,<<"firmware">>,
% <<"hotplug">>,<<"iked">>,<<"isakmpd">>,<<"ldap">>,
% <<"magic">>,<<"mail">>,<<"moduli">>,<<"monthly">>,
% <<"mtree">>,<<"netstart">>,<<"npppd">>,<<"pf.os">>,
% <<"ppp">>,<<"protocols">>,<<"rc">>,<<"rc.conf">>,<<"rc.d">>,
% <<...>>|...]}
% 6> alcove:readdir(Drv, [Pid], "/tmp").
% {error,enoent}
% '''
unveil(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
unveil,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc unveil(2): restrict filesystem view
%
% To disable unveil calls, use an empty list ([]) or, equivalently, an
% empty string ("").
%
% ```
% alcove:unveil(Drv, [Task], <<"/etc">>, <<"r">>),
% alcove:unveil(Drv, [Task], [], []).
% '''
%
% == Support ==
%
% • OpenBSD
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28978}
% 3> alcove:unveil(Drv, [Pid], <<"/etc">>, <<"r">>).
% ok
% 4> alcove:unveil(Drv, [Pid], [], []).
% ok
% 5> alcove:readdir(Drv, [Pid], "/etc").
% {ok,[<<".">>,<<"..">>,<<"acme">>,<<"amd">>,<<"authpf">>,
% <<"daily">>,<<"disktab">>,<<"examples">>,<<"firmware">>,
% <<"hotplug">>,<<"iked">>,<<"isakmpd">>,<<"ldap">>,
% <<"magic">>,<<"mail">>,<<"moduli">>,<<"monthly">>,
% <<"mtree">>,<<"netstart">>,<<"npppd">>,<<"pf.os">>,
% <<"ppp">>,<<"protocols">>,<<"rc">>,<<"rc.conf">>,<<"rc.d">>,
% <<...>>|...]}
% 6> alcove:readdir(Drv, [Pid], "/tmp").
% {error,enoent}
% '''
unveil(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
unveil,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc Retrieve the alcove version
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:version(Drv, []).
% <<"0.37.0">>
% '''
version(Drv, Pids) ->
case alcove_drv:call(Drv, Pids, version, [], infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids]);
Reply -> Reply
end.
% @doc Retrieve the alcove version
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> alcove:version(Drv, []).
% <<"0.37.0">>
% '''
version(Drv, Pids, Timeout) ->
case alcove_drv:call(Drv, Pids, version, [], Timeout) of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Timeout]);
Reply -> Reply
end.
% @doc waitpid(2): wait for process to change state
%
% Process state changes are handled by the alcove SIGCHLD event handler
% by default. To use waitpid/4,5, disable the signal handler:
%
% ```
% alcove:sigaction(Drv, [Pid], sigchld, sig_info)
% '''
%
% Note: if the default SIGCHLD handler is disabled, waitpid/4,5 should be
% called to reap zombie processes:
%
% ```
% alcove:waitpid(Drv, [], -1, [wnohang])
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28978}
% 3> alcove:sigaction(Drv, [Pid], sigchld, sig_info).
% {ok,sig_dfl}
% 4> alcove:execvp(Drv, [Pid], "sleep", ["sleep", "20"]).
% ok
% 5> alcove:waitpid(Drv, [], -1, []).
% {ok,28978,0,[{exit_status,0}]}
% '''
waitpid(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
waitpid,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc waitpid(2): wait for process to change state
%
% Process state changes are handled by the alcove SIGCHLD event handler
% by default. To use waitpid/4,5, disable the signal handler:
%
% ```
% alcove:sigaction(Drv, [Pid], sigchld, sig_info)
% '''
%
% Note: if the default SIGCHLD handler is disabled, waitpid/4,5 should be
% called to reap zombie processes:
%
% ```
% alcove:waitpid(Drv, [], -1, [wnohang])
% '''
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, Pid} = alcove:fork(Drv, []).
% {ok,28978}
% 3> alcove:sigaction(Drv, [Pid], sigchld, sig_info).
% {ok,sig_dfl}
% 4> alcove:execvp(Drv, [Pid], "sleep", ["sleep", "20"]).
% ok
% 5> alcove:waitpid(Drv, [], -1, []).
% {ok,28978,0,[{exit_status,0}]}
% '''
waitpid(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
waitpid,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.
% @doc write(2): write to a file descriptor
%
% Writes a buffer to a file descriptor and returns the number of bytes
% written.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, FD} = alcove:open(Drv, [], "/tmp/alcove-write-test", [o_wronly,o_creat], 8#644).
% {ok,6}
% 3> alcove:write(Drv, [], FD, <<"test">>).
% {ok,4}
% '''
write(Drv, Pids, Arg1, Arg2) ->
case alcove_drv:call(Drv,
Pids,
write,
[Arg1, Arg2],
infinity)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2]);
Reply -> Reply
end.
% @doc write(2): write to a file descriptor
%
% Writes a buffer to a file descriptor and returns the number of bytes
% written.
%
% == Examples ==
%
% ```
% 1> {ok, Drv} = alcove_drv:start().
% {ok,<0.177.0>}
% 2> {ok, FD} = alcove:open(Drv, [], "/tmp/alcove-write-test", [o_wronly,o_creat], 8#644).
% {ok,6}
% 3> alcove:write(Drv, [], FD, <<"test">>).
% {ok,4}
% '''
write(Drv, Pids, Arg1, Arg2, Timeout) ->
case alcove_drv:call(Drv,
Pids,
write,
[Arg1, Arg2],
Timeout)
of
{alcove_error, Error} ->
erlang:error(Error, [Drv, Pids, Arg1, Arg2, Timeout]);
Reply -> Reply
end.