Remove function versions with optional fork path

Enforce the use of the fork path. Having an optional fork path was nice
when working in the shell:

    {ok, Child} = alcove:fork(Drv).

Instead of:

    {ok, Child} = alcove:fork(Drv, []). % port process forks

However it introduced a few problems:

* made the interface inconsistent and ambiguous

    alcove:kill(Drv, Pid, 9)
    % vs
    alcove:kill(Drv, [], Pid, 9) % the port process is sending the signal

* calls could not have optional arguments

  Whether or not calls should have optional arguments is an open question
  but the optional fork path would have conflicting arities:

  For example, the last argument to mount/8 is used only by Solaris:

  % arity 6
  -spec mount(alcove_drv:ref(),iodata(),iodata(),iodata(),uint64_t() | [constant()],iodata()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
  % arity 7
  -spec mount(alcove_drv:ref(),iodata(),iodata(),iodata(),uint64_t() | [constant()],iodata(),iodata()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
  % arity 7
  -spec mount(alcove_drv:ref(),fork_path(),iodata(),iodata(),iodata(),uint64_t() | [constant()],iodata()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
  % arity 8
  -spec mount(alcove_drv:ref(),fork_path(),iodata(),iodata(),iodata(),uint64_t() | [constant()],iodata(),iodata()) -> 'ok' | {'error', file:posix() | 'unsupported'}.

* because of the ambiguity in arity, each call can't have an optional
  timeout

  call/5 sets a timeout of 'infinity'. The timeout isn't accessible from
  the "named" functions (e.g., fork, chdir, ...), which means that users
  who need the timeout will have to resort to using the call/5
  interface. An unfortunate side effect of using call/5 is that dialzyer
  won't be able to type check the arguments.

The result of removing the functions without the fork path is that the
code ends up being simpler and more consistent.
This commit is contained in:
Michael Santos
2015-07-19 09:37:55 -04:00
parent 8c83784bc2
commit d755ada152
12 changed files with 99 additions and 311 deletions

107
README.md
View File

@@ -19,7 +19,7 @@ Much like a shell, alcove waits for a command. For example, alcove can
be requested to fork(2):
```erlang
{ok, Child1} = alcove:fork(Drv).
{ok, Child1} = alcove:fork(Drv, []).
```
Now there are 2 processes in a parent/child relationship, sitting in
@@ -33,7 +33,6 @@ Child2 = alcove:getpid(Drv, [Child1,Child2]).
An empty fork path refers to the port process:
```erlang
% Same as doing: alcove:fork(Drv).
{ok, Child3} = alcove:fork(Drv, []).
```
@@ -157,7 +156,7 @@ sandbox(Drv) ->
sandbox(Drv, Argv) ->
{Path, Arg0, Args} = argv(Argv),
{ok, Child} = alcove:fork(Drv),
{ok, Child} = alcove:fork(Drv, []),
setlimits(Drv, Child),
chroot(Drv, Child, Path),
@@ -218,7 +217,7 @@ true
<<"sh: can't fork\n">>
% If we check the parent for events, we can see the child has exited
10> alcove:event(P).
10> alcove:event(P, []).
{signal,sigchld}
```
@@ -281,7 +280,7 @@ setlimits(Drv, Child) ->
sandbox(Drv, Argv) ->
{Path, Arg0, Args} = argv(Argv),
{ok, Child} = alcove:clone(Drv, [
{ok, Child} = alcove:clone(Drv, [], [
clone_newipc, % IPC
clone_newnet, % network
clone_newns, % mounts
@@ -350,15 +349,6 @@ alcove_drv
alcove
======
If any of these functions do not include the fork path, the call is
evaluated by the port. The following functions are equivalent:
alcove:getpid(Drv)
alcove:getpid(Drv, [])
alcove:chown(Drv, "/tmp/test", 8#600)
alcove:chown(Drv, [], "/tmp/test", 8#600)
Functions marked as operating system specific will return
{error,unsupported} on other platforms.
@@ -381,34 +371,28 @@ probably confuse the process.
Functions accepting a constant() will return {error, unsupported} if an
atom is used as the argument and is not found on the platform.
chdir(Drv, Path) -> ok | {error, posix()}
chdir(Drv, Pids, Path) -> ok | {error, posix()}
chdir(2) : change process current working directory.
chmod(Drv, Path, Mode) -> ok | {error, posix()}
chmod(Drv, Pids, Path, Mode) -> ok | {error, posix()}
chmod(2) : change file permissions
chown(Drv, Path, Owner, Group) -> ok | {error, posix()}
chown(Drv, Pids, Path, Owner, Group) -> ok | {error, posix()}
Types Owner = Group = non_neg_integer()
chown(2) : change file ownership
chroot(Drv, Path) -> ok | {error, posix()}
chroot(Drv, Pids, Path) -> ok | {error, posix()}
chroot(2) : change root directory
clearenv(Drv) -> ok | {error, posix()}
clearenv(Drv, Pids) -> ok | {error, posix()}
clearenv(3) : zero process environment
clone(Drv, Flags) -> {ok, integer()} | {error, posix() | unsupported}
clone(Drv, Pids, Flags) -> {ok, integer()} | {error, posix() | unsupported}
Types Flags = integer() | [constant()]
@@ -417,31 +401,26 @@ atom is used as the argument and is not found on the platform.
clone(2) : create a new process
clone_define(Drv, atom()) -> integer() | unknown
clone_define(Drv, Pids, atom()) -> integer() | unknown
Linux only.
Map symbols to integer constants.
close(Drv, FD) -> ok | {error, posix()}
close(Drv, Pids, FD) -> ok | {error, posix()}
close(2) : close a file descriptor.
environ(Drv) -> [binary()]
environ(Drv, Pids) -> [binary()]
environ(7) : return the process environment variables
event(Drv) -> term()
event(Drv, Pids) -> term()
event/1,2 is used to retrieve async messages returned from the
port, such as caught signals, the exit status or the termination
signal.
execve(Drv, Arg0, [Arg0, Args], Env) -> ok | {error, posix()}
execve(Drv, Pids, Arg0, [Arg0, Args], Env) -> ok | {error, posix()}
Types Arg0 = Args = iodata()
@@ -450,7 +429,6 @@ atom is used as the argument and is not found on the platform.
execve(2) : replace the process image, specifying the environment
for the new process image.
execvp(Drv, Arg0, [Arg0, Args]) -> ok | {error, posix()}
execvp(Drv, Pids, Arg0, [Arg0, Args]) -> ok | {error, posix()}
Types Arg0 = Args = iodata()
@@ -458,44 +436,36 @@ atom is used as the argument and is not found on the platform.
execvp(2) : replace the current process image using the search path
exit(Drv, Value) -> ok
exit(Drv, Pids, Value) -> ok
Types Value = integer()
exit(3) : cause the child process to exit
file_define(Drv, atom()) -> integer() | unknown
file_define(Drv, Pids, atom()) -> integer() | unknown
Constants for open(2).
fork(Drv) -> {ok, integer()} | {error, posix()}
fork(Drv, Pids) -> {ok, integer()} | {error, posix()}
fork(2) : create a new process
getcwd(Drv) -> {ok, binary()} | {error, posix()}
getcwd(Drv, Pids) -> {ok, binary()} | {error, posix()}
getcwd(3) : return the current working directory
getenv(Drv, iodata()) -> binary() | false
getenv(Drv, Pids, iodata()) -> binary() | false
getenv(3) : retrieve an environment variable
getgid(Drv) -> non_neg_integer()
getgid(Drv, Pids) -> non_neg_integer()
getgid(2) : retrieve the processes' group ID
gethostname(Drv) -> {ok, binary()} | {error, posix()}
gethostname(Drv, Pids) -> {ok, binary()} | {error, posix()}
gethostname(2) : retrieve the system hostname
getopt(Drv, Options) -> integer() | false
getopt(Drv, Pids, Options) -> integer() | false
Types Options = verbose | childlimit | exit_status | maxchild |
@@ -539,17 +509,14 @@ atom is used as the argument and is not found on the platform.
If a child process exits because of a signal, notify
the controlling Erlang process.
getpgrp(Drv) -> integer()
getpgrp(Drv, Pids) -> integer()
getpgrp(2) : retrieve the process group.
getpid(Drv) -> integer()
getpid(Drv, Pids) -> integer()
getpid(2) : retrieve the system PID of the process.
getpriority(Drv, Which, Who) -> {ok, Prio} | {error, posix() | unsupported}
getpriority(Drv, Pids, Which, Who) -> {ok, Prio} | {error, posix() | unsupported}
Types Which = constant()
@@ -558,7 +525,6 @@ atom is used as the argument and is not found on the platform.
getpriority(2) : retrieve scheduling priority of process,
process group or user
getresgid(Drv) -> {ok, RGID, EGID, SGID}
getresgid(Drv, Pids) -> {ok, RGID, EGID, SGID}
Types RGID = EGID = SGID = non_neg_integer()
@@ -567,7 +533,6 @@ atom is used as the argument and is not found on the platform.
Supported on Linux and BSD's.
getresuid(Drv) -> {ok, RUID, EUID, SUID}
getresuid(Drv, Pids) -> {ok, RUID, EUID, SUID}
Types RUID = EUID = SUID = non_neg_integer()
@@ -576,7 +541,6 @@ atom is used as the argument and is not found on the platform.
Supported on Linux and BSD's.
getrlimit(Drv, constant()) -> {ok, #alcove_rlimit{}} | {error, posix() | unsupported}
getrlimit(Drv, Pids, constant()) -> {ok, #alcove_rlimit{}} | {error, posix() | unsupported}
getrlimit(2) : retrive the resource limits for a process. Returns
@@ -589,37 +553,30 @@ atom is used as the argument and is not found on the platform.
max = integer()
}
getsid(Drv, Pid) -> {ok, integer()} | {error, posix()}
getsid(Drv, Pids, Pid) -> {ok, integer()} | {error, posix()}
getsid(2) : retrieve the session ID
getuid(Drv) -> integer()
getuid(Drv, Pids) -> integer()
getuid(2) : returns the process user ID
kill(Drv, Pid, Signal) -> ok | {error, posix() | unsupported}
kill(Drv, Pids, Pid, Signal) -> ok | {error, posix() | unsupported}
Types Signal = constant()
kill(2) : terminate a process
lseek(Drv, FD, Offset, Whence) -> ok | {error, posix()}
lseek(Drv, Pids, FD, Offset, Whence) -> ok | {error, posix()}
Types Offset = Whence = integer()
lseek(2) : set file offset for read/write
mkdir(Drv, Path, Mode) -> ok | {error, posix()}
mkdir(Drv, Pids, Path, Mode) -> ok | {error, posix()}
mkdir(2) : create a directory
mount(Drv, Source, Target, FSType, Flags, Data, Options) -> ok
| {error, posix() | unsupported}
mount(Drv, Pids, Source, Target, FSType, Flags, Data, Options) -> ok
| {error, posix() | unsupported}
@@ -637,7 +594,6 @@ atom is used as the argument and is not found on the platform.
as a string of comma separated values terminated by a NULL.
Other platforms ignore the Options parameter.
mount_define(Drv, Flag) -> integer() | unknown
mount_define(Drv, Pids, Flag) -> integer() | unknown
Types Flag = rdonly | nosuid | noexec | noatime | ...
@@ -645,12 +601,11 @@ atom is used as the argument and is not found on the platform.
Convert flag names to integers. The lower case atoms are used
for portability:
alcove:mount_define(Drv, rdonly)
alcove:mount_define(Drv, [], rdonly)
'rdonly' is mapped to MS_RDONLY on Linux and MNT_RDONLY on
FreeBSD.
open(Drv, Path, Flags, Mode) -> {ok, integer()} | {error, posix() | unsupported}
open(Drv, Pids, Path, Flags, Mode) -> {ok, integer()} | {error, posix() | unsupported}
Types Flags = integer() | [constant()]
@@ -660,15 +615,12 @@ atom is used as the argument and is not found on the platform.
Lists of values are OR'ed:
alcove:open(Drv, "/tmp/test", [o_wronly,o_creat], 8#644)
alcove:open(Drv, [], "/tmp/test", [o_wronly,o_creat], 8#644)
pid(Drv) -> [Pid]
pid(Drv, Pids) -> [Pid]
Returns the list of child PIDs for this process.
prctl(Drv, Option, Arg2, Arg3, Arg4, Arg5) ->
{ok, integer(), Val2, Val3, Val4, Val5} | {error, posix() | unsupported}
prctl(Drv, Pids, Option, Arg2, Arg3, Arg4, Arg5) ->
{ok, integer(), Val2, Val3, Val4, Val5} | {error, posix() | unsupported}
@@ -714,7 +666,7 @@ atom is used as the argument and is not found on the platform.
% See test/alcove_seccomp_tests.erl for all the syscalls
% required for the port process to run
Arch = alcove:define(Drv, alcove:audit_arch()),
Arch = alcove:define(Drv, [], alcove:audit_arch()),
Filter = [
?VALIDATE_ARCHITECTURE(Arch),
?EXAMINE_SYSCALL,
@@ -722,7 +674,7 @@ atom is used as the argument and is not found on the platform.
sys_write
],
{ok,_,_,_,_,_} = alcove:prctl(Drv, pr_set_no_new_privs, 1, 0, 0, 0),
{ok,_,_,_,_,_} = alcove:prctl(Drv, [], pr_set_no_new_privs, 1, 0, 0, 0),
Pad = (erlang:system_info({wordsize,external}) - 2) * 8,
Prog = [
@@ -730,37 +682,31 @@ atom is used as the argument and is not found on the platform.
<<0:Pad>>,
{ptr, list_to_binary(Filter)}
],
alcove:prctl(Drv, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).
alcove:prctl(Drv, [], pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).
prctl_define(Drv, atom()) -> integer() | unknown
prctl_define(Drv, Pids, atom()) -> integer() | unknown
Convert prctl option names to integers.
read(Drv, Fd, Count) -> {ok, binary()} | {error, posix()}
read(Drv, Pids, Fd, Count) -> {ok, binary()} | {error, posix()}
Types Count = non_neg_integer()
read(2) : read bytes from a file descriptor
readdir(Drv, Path) -> {ok, [binary()]} | {error, posix()}
readdir(Drv, Pids, Path) -> {ok, [binary()]} | {error, posix()}
readdir(3) : retrieve list of objects in a directory
rlimit_define(Drv, atom()) -> integer() | unknown
rlimit_define(Drv, Pids, atom()) -> integer() | unknown
Convert an RLIMIT_* flag to an integer().
rmdir(Drv, Path) -> ok | {error, posix()}
rmdir(Drv, Pids, Path) -> ok | {error, posix()}
rmdir(2) : delete a directory
select(Drv, Readfds, Writefds, Exceptfds, Timeout) -> {ok, Readfds, Writefds, Exceptfds} | {error, posix()}
select(Drv, Pids, Readfds, Writefds, Exceptfds, Timeout) -> {ok, Readfds, Writefds, Exceptfds} | {error, posix()}
Types Readfds = Writefds = Exceptfds = [] | [integer()]
@@ -780,7 +726,6 @@ atom is used as the argument and is not found on the platform.
sec : number of seconds to wait
usec : number of microseconds to wait
setenv(Drv, Name, Value, Overwrite) -> ok | {error, posix()}
setenv(Drv, Pids, Name, Value, Overwrite) -> ok | {error, posix()}
Types Name = Value = iodata()
@@ -788,26 +733,22 @@ atom is used as the argument and is not found on the platform.
setenv(3) : set an environment variable
setgid(Drv, Gid) -> ok | {error, posix()}
setgid(Drv, Pids, Gid) -> ok | {error, posix()}
Types Gid = non_neg_integer()
setgid(2) : set the GID of the process
setpgid(Drv, Pid, Pgid) -> ok | {error, posix()}
setpgid(Drv, Pids, Pid, Pgid) -> ok | {error, posix()}
Types Pgid = integer()
setpgid(2) : set process group
setsid(Drv) -> {ok, Pid} | {error, posix()}
setsid(Drv, Pids) -> {ok, Pid} | {error, posix()}
setsid(2) : create a new session
sethostname(Drv, Hostname) -> ok | {error, posix()}
sethostname(Drv, Pids, Hostname) -> ok | {error, posix()}
Types Hostname = iodata()
@@ -816,13 +757,12 @@ atom is used as the argument and is not found on the platform.
This function is probably only useful if running in a uts namespace:
{ok, Child} = alcove:clone(Drv, [clone_newuts]),
{ok, Child} = alcove:clone(Drv, [], [clone_newuts]),
ok = alcove:sethostname(Drv, [Child], "test"),
Hostname1 = alcove:gethostname(Drv),
Hostname1 = alcove:gethostname(Drv, []),
Hostname2 = alcove:gethostname(Drv, [Child]),
Hostname1 =/= Hostname2.
setns(Drv, Path) -> ok | {error, posix()}
setns(Drv, Pids, Path) -> ok | {error, posix()}
Linux only.
@@ -844,19 +784,17 @@ atom is used as the argument and is not found on the platform.
For example, to attach to another process' network namespace:
{ok, Child1} = alcove:clone(Drv, [clone_newnet]),
{ok, Child2} = alcove:fork(Drv),
{ok, Child1} = alcove:clone(Drv, [], [clone_newnet]),
{ok, Child2} = alcove:fork(Drv, []),
% Move Child2 into the Child1 network namespace
ok = alcove:setns(Drv, [Child2],
["/proc/", integer_to_list(Child1), "/ns/net"]).
setopt(Drv, Opt, Val) -> boolean()
setopt(Drv, Pids, Opt, Val) -> boolean()
Set port options. See getopt/2,3 for the list of options.
setpriority(Drv, Which, Who, Prio) -> ok | {error, posix() | unsupported}
setpriority(Drv, Pids, Which, Who, Prio) -> ok | {error, posix() | unsupported}
Types Which = constant()
@@ -865,7 +803,6 @@ atom is used as the argument and is not found on the platform.
setpriority(2) : set scheduling priority of process, process
group or user
setproctitle(Drv, Name) -> ok
setproctitle(Drv, Pids, Name) -> ok
Types Name = iodata()
@@ -876,10 +813,9 @@ atom is used as the argument and is not found on the platform.
On Linux, use prctl/6,7:
{ok,Fork} = alcove:fork(Drv),
{ok,Fork} = alcove:fork(Drv, []),
alcove:prctl(Drv, [Fork], pr_set_name, <<"pseudonym">>, 0,0,0).
setresgid(Drv, RGID, EGID, SGID) -> ok | {error, posix()}
setresgid(Drv, Pids, RGID, EGID, SGID) -> ok | {error, posix()}
Types RGID = EGID = SGID = non_neg_integer()
@@ -888,7 +824,6 @@ atom is used as the argument and is not found on the platform.
Supported on Linux and BSD's.
setresuid(Drv, RUID, EUID, SUID) -> ok | {error, posix()}
setresuid(Drv, Pids, RUID, EUID, SUID) -> ok | {error, posix()}
Types RUID = EUID = SUID = non_neg_integer()
@@ -897,7 +832,6 @@ atom is used as the argument and is not found on the platform.
Supported on Linux and BSD's.
setrlimit(Drv, Resource, Limit) -> ok | {error, posix() | unsupported}
setrlimit(Drv, Pids, Resource, Limit) -> ok | {error, posix() | unsupported}
Types Resource = constant()
@@ -905,14 +839,12 @@ atom is used as the argument and is not found on the platform.
setrlimit(2) : set a resource limit
setuid(Drv, UID) -> ok | {error, posix()}
setuid(Drv, Pids, UID) -> ok | {error, posix()}
Types UID = non_neg_integer()
setuid(2) : change UID
sigaction(Drv, Signum, Handler) -> ok | {error, posix() | unsupported}
sigaction(Drv, Pids, Signum, Handler) -> ok | {error, posix() | unsupported}
Types Signum = constant()
@@ -929,29 +861,24 @@ atom is used as the argument and is not found on the platform.
Multiple caught signals may be reported as one event.
signal_constant(Drv, integer()) -> atom() | unknown
signal_constant(Drv, Pids, integer()) -> atom() | unknown
Convert integers to signal names.
signal_define(Drv, atom()) -> integer() | unknown
signal_define(Drv, Pids, atom()) -> integer() | unknown
Convert signal names to integers.
umount(Drv, Path) -> ok | {error, posix()}
umount(Drv, Pids, Path) -> ok | {error, posix()}
umount(2) : unmount a filesystem
On BSD systems, calls unmount(2).
unsetenv(Drv, Name) -> ok | {error, posix()}
unsetenv(Drv, Pids, Name) -> ok | {error, posix()}
unsetenv(3) : remove an environment variable
unshare(Drv, Flags) -> ok | {error, posix() | unsupported}
unshare(Drv, Pids, Flags) -> ok | {error, posix() | unsupported}
Types Flags = constant()
@@ -962,16 +889,14 @@ atom is used as the argument and is not found on the platform.
unshare(2) lets you make a new namespace without calling clone(2):
ok = alcove:unshare(Drv, [clone_newnet]).
ok = alcove:unshare(Drv, [], [clone_newnet]).
% The port is now running in a namespace without network access.
version(Drv) -> binary()
version(Drv, Pids) -> binary()
Retrieves the alcove version.
write(Drv, FD, Buf) -> {ok, Count} | {error, posix()}
write(Drv, Pids, FD, Buf) -> {ok, Count} | {error, posix()}
Types Buf = iodata()
@@ -983,8 +908,6 @@ atom is used as the argument and is not found on the platform.
The alcove module functions can be rewritten to use call/2,3,4,5 which
allows setting timeouts.
call(Drv, Call) -> term()
call(Drv, Call, Argv) -> term()
call(Drv, Pids, Call, Argv) -> term()
call(Drv, Pids, Call, Argv, Timeout) -> term()

View File

@@ -56,11 +56,6 @@ mkerl(File, Proto) ->
]),
Comment_gen = erl_syntax:comment([" Generated functions"]),
Exports_gen0 = erl_syntax:attribute(erl_syntax:atom(export), [
erl_syntax:list([
erl_syntax:arity_qualifier(erl_syntax:atom(Fun), erl_syntax:integer(Arity+1))
|| {Fun, Arity} <- Calls ])
]),
Exports_gen1 = erl_syntax:attribute(erl_syntax:atom(export), [
erl_syntax:list([
@@ -73,14 +68,6 @@ mkerl(File, Proto) ->
% name(Drv, ...) -> alcove:call(Drv, [], Fun, [...])
Arg = arg("Arg", Arity),
Pattern0 = [erl_syntax:variable("Drv")|Arg],
Body0 = erl_syntax:application(
erl_syntax:atom(call),
[erl_syntax:variable("Drv"), erl_syntax:nil(),
erl_syntax:atom(Fun), erl_syntax:list(Arg)]
),
Clause0 = erl_syntax:clause(Pattern0, [], [Body0]),
% name(Drv, Pids, ...) -> alcove:call(Drv, Pids, Fun, [...])
Pattern1 = [erl_syntax:variable("Drv"), erl_syntax:variable("Pids")|Arg],
Body1 = erl_syntax:application(
@@ -90,8 +77,7 @@ mkerl(File, Proto) ->
),
Clause1 = erl_syntax:clause(Pattern1, [], [Body1]),
[erl_syntax:function(erl_syntax:atom(Fun), [Clause0]),
erl_syntax:function(erl_syntax:atom(Fun), [Clause1])]
[erl_syntax:function(erl_syntax:atom(Fun), [Clause1])]
end || {Fun, Arity} <- Calls ],
@@ -106,7 +92,6 @@ mkerl(File, Proto) ->
Exports_static,
Comment_gen,
Exports_gen0,
Exports_gen1,
Static,
@@ -146,13 +131,13 @@ b2i(N) when is_binary(N) ->
static_exports() ->
[{audit_arch,0},
{define,2},{define,3},
{stdin,2}, {stdin,3},
{stdout,1}, {stdout,2}, {stdout,3},
{stderr,1}, {stderr,2}, {stderr,3},
{define,3},
{stdin,3},
{stdout,2}, {stdout,3},
{stderr,2}, {stderr,3},
{eof,2}, {eof,3},
{event,1}, {event,2}, {event,3},
{call,2}, {call,3}, {call,4}, {call,5}].
{event,2}, {event,3},
{call,4}, {call,5}].
static() ->
[ static({Fun, Arity}) || {Fun, Arity} <- static_exports() ].
@@ -173,11 +158,6 @@ static({audit_arch,0}) ->
proplists:get_value({Arch,OS,Wordsize}, Arches, unsupported).
";
static({define,2}) ->
"
define(Drv, Const) ->
define(Drv, [], Const).
";
static({define,3}) ->
"
define(Drv, Pids, Const) when is_atom(Const) ->
@@ -215,22 +195,12 @@ const(\"noexec\") -> mount_define;
const(\"noatime\") -> mount_define.
";
static({stdin,2}) ->
"
stdin(Drv, Data) ->
stdin(Drv, [], Data).
";
static({stdin,3}) ->
"
stdin(Drv, Pids, Data) ->
alcove_drv:stdin(Drv, Pids, Data).
";
static({stdout,1}) ->
"
stdout(Drv) ->
stdout(Drv, [], 0).
";
static({stdout,2}) ->
"
stdout(Drv, Pids) ->
@@ -242,11 +212,6 @@ stdout(Drv, Pids, Timeout) ->
alcove_drv:stdout(Drv, Pids, Timeout).
";
static({stderr,1}) ->
"
stderr(Drv) ->
stderr(Drv, [], 0).
";
static({stderr,2}) ->
"
stderr(Drv, Pids) ->
@@ -286,11 +251,6 @@ eof_1(Drv, Pids, #alcove_pid{stderr = FD}, stderr) ->
close(Drv, Pids, FD).
";
static({event,1}) ->
"
event(Drv) ->
event(Drv, [], 0).
";
static({event,2}) ->
"
event(Drv, Pids) ->
@@ -302,16 +262,6 @@ event(Drv, Pids, Timeout) ->
alcove_drv:event(Drv, Pids, Timeout).
";
static({call,2}) ->
"
call(Drv, Command) ->
call(Drv, [], Command, [], infinity).
";
static({call,3}) ->
"
call(Drv, Command, Argv) ->
call(Drv, [], Command, Argv, infinity).
";
static({call,4}) ->
"
call(Drv, Pids, Command, Argv) ->
@@ -379,229 +329,155 @@ specs() ->
-spec audit_arch() -> atom().
-spec call(alcove_drv:ref(),atom()) -> term().
-spec call(alcove_drv:ref(),atom(),list()) -> term().
-spec call(alcove_drv:ref(),fork_path(),atom(),list()) -> term().
-spec call(alcove_drv:ref(),fork_path(),atom(),list(),timeout()) -> term().
-spec chdir(alcove_drv:ref(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec chdir(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec chmod(alcove_drv:ref(),iodata(),mode_t()) -> 'ok' | {'error', file:posix()}.
-spec chmod(alcove_drv:ref(),fork_path(),iodata(),mode_t()) -> 'ok' | {'error', file:posix()}.
-spec chown(alcove_drv:ref(),iodata(),uid_t(),gid_t()) -> 'ok' | {'error', file:posix()}.
-spec chown(alcove_drv:ref(),fork_path(),iodata(),uid_t(),gid_t()) -> 'ok' | {'error', file:posix()}.
-spec chroot(alcove_drv:ref(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec chroot(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec clearenv(alcove_drv:ref()) -> 'ok' | {'error', file:posix()}.
-spec clearenv(alcove_drv:ref(),fork_path()) -> 'ok' | {'error', file:posix()}.
-spec clone(alcove_drv:ref(),int32_t() | [constant()]) -> {'ok', pid_t()} | {'error', file:posix() | 'unsupported'}.
-spec clone(alcove_drv:ref(),fork_path(),int32_t() | [constant()]) -> {'ok', pid_t()} | {'error', file:posix() | 'unsupported'}.
-spec clone_define(alcove_drv:ref(),atom()) -> 'unknown' | int32_t().
-spec clone_define(alcove_drv:ref(),fork_path(),atom()) -> 'unknown' | int32_t().
-spec close(alcove_drv:ref(),fd()) -> 'ok' | {'error', file:posix()}.
-spec close(alcove_drv:ref(),fork_path(),fd()) -> 'ok' | {'error', file:posix()}.
-spec define(alcove_drv:ref(),atom() | [atom()]) -> 'unknown' | integer().
-spec define(alcove_drv:ref(),fork_path(),atom() | [atom()]) -> 'unknown' | integer().
-spec environ(alcove_drv:ref()) -> [binary()].
-spec environ(alcove_drv:ref(),fork_path()) -> [binary()].
-spec eof(alcove_drv:ref(),fork_path()) -> 'ok' | {'error',file:posix()}.
-spec eof(alcove_drv:ref(),fork_path(),'stdin' | 'stdout' | 'stderr') -> 'ok' | {'error',file:posix()}.
-spec errno_id(alcove_drv:ref(),int32_t()) -> file:posix().
-spec errno_id(alcove_drv:ref(),fork_path(),int32_t()) -> file:posix().
-spec event(alcove_drv:ref()) -> term().
-spec event(alcove_drv:ref(),fork_path()) -> term().
-spec event(alcove_drv:ref(),fork_path(),timeout()) -> term().
-spec execve(alcove_drv:ref(),iodata(),[iodata()],[iodata()]) -> 'ok'.
-spec execve(alcove_drv:ref(),fork_path(),iodata(),[iodata()],[iodata()]) -> 'ok'.
-spec execvp(alcove_drv:ref(),iodata(),[iodata()]) -> 'ok'.
-spec execvp(alcove_drv:ref(),fork_path(),iodata(),[iodata()]) -> 'ok'.
-spec exit(alcove_drv:ref(),int32_t()) -> 'ok'.
-spec exit(alcove_drv:ref(),fork_path(),int32_t()) -> 'ok'.
-spec file_define(alcove_drv:ref(),atom()) -> non_neg_integer() | 'unknown'.
-spec file_define(alcove_drv:ref(),fork_path(),atom()) -> non_neg_integer() | 'unknown'.
-spec fork(alcove_drv:ref()) -> {'ok', pid_t()} | {'error', file:posix()}.
-spec fork(alcove_drv:ref(),fork_path()) -> {'ok', pid_t()} | {'error', file:posix()}.
-spec getcwd(alcove_drv:ref()) -> {'ok', binary()} | {'error', file:posix()}.
-spec getcwd(alcove_drv:ref(),fork_path()) -> {'ok', binary()} | {'error', file:posix()}.
-spec getenv(alcove_drv:ref(),iodata()) -> binary() | 'false'.
-spec getenv(alcove_drv:ref(),fork_path(),iodata()) -> binary() | 'false'.
-spec getgid(alcove_drv:ref()) -> gid_t().
-spec getgid(alcove_drv:ref(),fork_path()) -> gid_t().
-spec gethostname(alcove_drv:ref()) -> {'ok', binary()} | {'error', file:posix()}.
-spec gethostname(alcove_drv:ref(),fork_path()) -> {'ok', binary()} | {'error', file:posix()}.
-spec getopt(alcove_drv:ref(),atom()) -> 'false' | non_neg_integer().
-spec getopt(alcove_drv:ref(),fork_path(),atom()) -> 'false' | non_neg_integer().
-spec getpgrp(alcove_drv:ref()) -> pid_t().
-spec getpgrp(alcove_drv:ref(),fork_path()) -> pid_t().
-spec getpid(alcove_drv:ref()) -> pid_t().
-spec getpid(alcove_drv:ref(),fork_path()) -> pid_t().
-spec getpriority(alcove_drv:ref(),constant(),int32_t()) -> {'ok',int32_t()} | {'error', file:posix() | 'unsupported'}.
-spec getpriority(alcove_drv:ref(),fork_path(),constant(),int32_t()) -> {'ok',int32_t()} | {'error', file:posix() | 'unsupported'}.
-spec getresgid(alcove_drv:ref()) -> {'ok', gid_t(), gid_t(), gid_t()} | {'error', file:posix()}.
-spec getresgid(alcove_drv:ref(), fork_path()) -> {'ok', gid_t(), gid_t(), gid_t()} | {'error', file:posix()}.
-spec getresuid(alcove_drv:ref()) -> {'ok', uid_t(), uid_t(), uid_t()} | {'error', file:posix()}.
-spec getresuid(alcove_drv:ref(), fork_path()) -> {'ok', uid_t(), uid_t(), uid_t()} | {'error', file:posix()}.
-spec getrlimit(alcove_drv:ref(),constant()) -> {'ok', #alcove_rlimit{}} | {'error', file:posix() | 'unsupported'}.
-spec getrlimit(alcove_drv:ref(),fork_path(),constant()) -> {'ok', #alcove_rlimit{}} | {'error', file:posix() | 'unsupported'}.
-spec getsid(alcove_drv:ref(), pid_t()) -> {'ok', pid_t()} | {'error', file:posix()}.
-spec getsid(alcove_drv:ref(), fork_path(), pid_t()) -> {'ok', pid_t()} | {'error', file:posix()}.
-spec getuid(alcove_drv:ref()) -> uid_t().
-spec getuid(alcove_drv:ref(),fork_path()) -> uid_t().
-spec kill(alcove_drv:ref(), pid_t(), constant()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec kill(alcove_drv:ref(), fork_path(), pid_t(), constant()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec lseek(alcove_drv:ref(),fd(),off_t(),int32_t()) -> 'ok' | {'error', file:posix()}.
-spec lseek(alcove_drv:ref(),fork_path(),fd(),off_t(),int32_t()) -> 'ok' | {'error', file:posix()}.
-spec mkdir(alcove_drv:ref(),iodata(),mode_t()) -> 'ok' | {'error', file:posix()}.
-spec mkdir(alcove_drv:ref(),fork_path(),iodata(),mode_t()) -> 'ok' | {'error', file:posix()}.
-spec mount(alcove_drv:ref(),iodata(),iodata(),iodata(),uint64_t() | [constant()],iodata(),iodata()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec mount(alcove_drv:ref(),fork_path(),iodata(),iodata(),iodata(),uint64_t() | [constant()],iodata(),iodata()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec mount_define(alcove_drv:ref(),atom()) -> 'unknown' | uint64_t().
-spec mount_define(alcove_drv:ref(),fork_path(),atom()) -> 'unknown' | uint64_t().
-spec open(alcove_drv:ref(),iodata(),int32_t() | [constant()],integer()) -> {'ok',fd()} | {'error', file:posix() | 'unsupported'}.
-spec open(alcove_drv:ref(),fork_path(),iodata(),int32_t() | [constant()],mode_t()) -> {'ok',fd()} | {'error', file:posix() | 'unsupported'}.
-spec pid(alcove_drv:ref()) -> [#alcove_pid{}].
-spec pid(alcove_drv:ref(),fork_path()) -> [#alcove_pid{}].
-spec pivot_root(alcove_drv:ref(),iodata(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec pivot_root(alcove_drv:ref(),fork_path(),iodata(),iodata()) -> 'ok' | {'error', file:posix()}.
-type prctl_arg() :: [binary() | {ptr, binary() | non_neg_integer()} ] | binary() | integer() | atom().
-type prctl_val() :: binary() | integer().
-spec prctl(alcove_drv:ref(),constant(),prctl_arg(),prctl_arg(),prctl_arg(),prctl_arg()) -> {'ok',integer(),prctl_val(),prctl_val(),prctl_val(),prctl_val()} | {'error', file:posix() | 'unsupported'}.
-spec prctl(alcove_drv:ref(),fork_path(),constant(),prctl_arg(),prctl_arg(),prctl_arg(),prctl_arg()) -> {'ok',integer(),prctl_val(),prctl_val(),prctl_val(),prctl_val()} | {'error', file:posix() | 'unsupported'}.
-spec prctl_define(alcove_drv:ref(),atom()) -> 'unknown' | non_neg_integer().
-spec prctl_define(alcove_drv:ref(),fork_path(),atom()) -> 'unknown' | non_neg_integer().
-spec read(alcove_drv:ref(),fd(),size_t()) -> {'ok', binary()} | {'error', file:posix()}.
-spec read(alcove_drv:ref(),fork_path(),fd(),size_t()) -> {'ok', binary()} | {'error', file:posix()}.
-spec readdir(alcove_drv:ref(),iodata()) -> {'ok', [binary()]} | {'error', file:posix()}.
-spec readdir(alcove_drv:ref(),fork_path(),iodata()) -> {'ok', [binary()]} | {'error', file:posix()}.
-spec rmdir(alcove_drv:ref(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec rmdir(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec rlimit_define(alcove_drv:ref(),atom()) -> 'unknown' | non_neg_integer().
-spec rlimit_define(alcove_drv:ref(),fork_path(),atom()) -> 'unknown' | non_neg_integer().
-spec select(alcove_drv:ref(),[fd_set()],[fd_set()],[fd_set()],
<<>> | #alcove_timeval{}) -> {ok, [fd_set()], [fd_set()], [fd_set()]} | {'error', file:posix()}.
-spec select(alcove_drv:ref(),fork_path(),[fd_set()],[fd_set()],[fd_set()],
<<>> | #alcove_timeval{}) -> {ok, [fd_set()], [fd_set()], [fd_set()]} | {'error', file:posix()}.
-spec setenv(alcove_drv:ref(),iodata(),iodata(),int32_t()) -> 'ok' | {'error', file:posix()}.
-spec setenv(alcove_drv:ref(),fork_path(),iodata(),iodata(),int32_t()) -> 'ok' | {'error', file:posix()}.
-spec setgid(alcove_drv:ref(),gid_t()) -> 'ok' | {'error', file:posix()}.
-spec setgid(alcove_drv:ref(),fork_path(),gid_t()) -> 'ok' | {'error', file:posix()}.
-spec sethostname(alcove_drv:ref(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec sethostname(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec setns(alcove_drv:ref(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec setns(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {'error', file:posix()}.
-spec setopt(alcove_drv:ref(),atom(), non_neg_integer()) -> boolean().
-spec setopt(alcove_drv:ref(),fork_path(),atom(),non_neg_integer()) -> boolean().
-spec setpgid(alcove_drv:ref(),pid_t(),pid_t()) -> 'ok' | {'error', file:posix()}.
-spec setpgid(alcove_drv:ref(),fork_path(),pid_t(),pid_t()) -> 'ok' | {'error', file:posix()}.
-spec setpriority(alcove_drv:ref(),constant(),int32_t(),int32_t()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec setpriority(alcove_drv:ref(),fork_path(),constant(),int32_t(),int32_t()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec setproctitle(alcove_drv:ref(),iodata()) -> 'ok'.
-spec setproctitle(alcove_drv:ref(),fork_path(),iodata()) -> 'ok'.
-spec setresgid(alcove_drv:ref(),gid_t(),gid_t(),gid_t()) -> 'ok' | {'error', file:posix()}.
-spec setresgid(alcove_drv:ref(),fork_path(),gid_t(),gid_t(),gid_t()) -> 'ok' | {'error', file:posix()}.
-spec setresuid(alcove_drv:ref(),uid_t(),uid_t(),uid_t()) -> 'ok' | {'error', file:posix()}.
-spec setresuid(alcove_drv:ref(),fork_path(),uid_t(),uid_t(),uid_t()) -> 'ok' | {'error', file:posix()}.
-spec setrlimit(alcove_drv:ref(),constant(),#alcove_rlimit{}) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec setrlimit(alcove_drv:ref(),fork_path(),constant(),#alcove_rlimit{}) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec setsid(alcove_drv:ref()) -> {ok,pid_t()} | {error, file:posix()}.
-spec setsid(alcove_drv:ref(),fork_path()) -> {ok,pid_t()} | {error, file:posix()}.
-spec setuid(alcove_drv:ref(),uid_t()) -> 'ok' | {'error', file:posix()}.
-spec setuid(alcove_drv:ref(),fork_path(),uid_t()) -> 'ok' | {'error', file:posix()}.
-spec sigaction(alcove_drv:ref(),constant(),atom()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec sigaction(alcove_drv:ref(),fork_path(),constant(),atom()) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec signal_constant(alcove_drv:ref(),non_neg_integer()) -> 'unknown' | atom().
-spec signal_constant(alcove_drv:ref(),fork_path(),non_neg_integer()) -> 'unknown' | atom().
-spec signal_define(alcove_drv:ref(),atom()) -> 'unknown' | non_neg_integer().
-spec signal_define(alcove_drv:ref(),fork_path(),atom()) -> 'unknown' | non_neg_integer().
-spec syscall_define(alcove_drv:ref(),atom()) -> 'unknown' | non_neg_integer().
-spec syscall_define(alcove_drv:ref(),fork_path(),atom()) -> 'unknown' | non_neg_integer().
-spec stderr(alcove_drv:ref()) -> 'false' | binary().
-spec stderr(alcove_drv:ref(),fork_path()) -> 'false' | binary().
-spec stderr(alcove_drv:ref(),fork_path(),timeout()) -> 'false' | binary().
-spec stdin(alcove_drv:ref(),iodata()) -> 'true'.
-spec stdin(alcove_drv:ref(),fork_path(),iodata()) -> 'true'.
-spec stdout(alcove_drv:ref()) -> 'false' | binary().
-spec stdout(alcove_drv:ref(),fork_path()) -> 'false' | binary().
-spec stdout(alcove_drv:ref(),fork_path(),timeout()) -> 'false' | binary().
-spec umount(alcove_drv:ref(),iodata()) -> 'ok' | {error, file:posix()}.
-spec umount(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {error, file:posix()}.
-spec unsetenv(alcove_drv:ref(),iodata()) -> 'ok' | {error, file:posix()}.
-spec unsetenv(alcove_drv:ref(),fork_path(),iodata()) -> 'ok' | {error, file:posix()}.
-spec unshare(alcove_drv:ref(),int32_t() | [constant()]) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec unshare(alcove_drv:ref(),fork_path(),int32_t() | [constant()]) -> 'ok' | {'error', file:posix() | 'unsupported'}.
-spec write(alcove_drv:ref(),fd(),iodata()) -> {'ok', ssize_t()} | {'error', file:posix()}.
-spec write(alcove_drv:ref(),fork_path(),fd(),iodata()) -> {'ok', ssize_t()} | {'error', file:posix()}.
-spec version(alcove_drv:ref()) -> binary().
-spec version(alcove_drv:ref(),fork_path()) -> binary().
".

View File

@@ -27,7 +27,7 @@ sandbox(Drv) ->
sandbox(Drv, Argv) ->
{Path, Arg0, Args} = argv(Argv),
{ok, Child} = alcove:fork(Drv),
{ok, Child} = alcove:fork(Drv, []),
setlimits(Drv, Child),
chroot(Drv, Child, Path),

View File

@@ -60,7 +60,7 @@ start(GPIO, N) ->
clone_newpid,
clone_newuts
],
{ok, Child} = alcove:clone(Drv, Flags),
{ok, Child} = alcove:clone(Drv, [], Flags),
ok = alcove:chroot(Drv, [Child],
["/sys/class/gpio/gpio", integer_to_list(GPIO)]),
@@ -72,16 +72,16 @@ start(GPIO, N) ->
ok = alcove:setuid(Drv, [Child], Id),
% Drop privs in the port
{ok, UFD} = alcove:open(Drv, "/sys/class/gpio/unexport",
{ok, UFD} = alcove:open(Drv, [], "/sys/class/gpio/unexport",
[o_wronly,o_cloexec], 0),
ok = alcove:unshare(Drv, Flags),
ok = alcove:chroot(Drv, "priv"),
ok = alcove:chdir(Drv, "/"),
ok = alcove:unshare(Drv, [], Flags),
ok = alcove:chroot(Drv, [], "priv"),
ok = alcove:chdir(Drv, [], "/"),
Id1 = id(),
ok = alcove:setgid(Drv, Id1),
ok = alcove:setuid(Drv, Id1),
ok = alcove:setgid(Drv, [], Id1),
ok = alcove:setuid(Drv, [], Id1),
strobe(#state{
drv = Drv,
@@ -96,8 +96,8 @@ strobe(#state{drv = Drv, pid = Child, direction = FD,
unexport = UFD, gpio = GPIO}, 0) ->
alcove:write(Drv, [Child], FD, <<"low">>),
alcove:close(Drv, [Child], FD),
{ok, _} = alcove:write(Drv, UFD, integer_to_list(GPIO)),
alcove:close(Drv, UFD),
{ok, _} = alcove:write(Drv, [], UFD, integer_to_list(GPIO)),
alcove:close(Drv, [], UFD),
alcove_drv:stop(Drv);
strobe(#state{drv = Drv, pid = Child, direction = FD} = State, N) ->
timer:sleep(100),
@@ -110,10 +110,10 @@ id() ->
crypto:rand_uniform(16#f0000000, 16#f000ffff).
export(Drv, Pin) ->
{ok, FD} = alcove:open(Drv, "/sys/class/gpio/export",
{ok, FD} = alcove:open(Drv, [], "/sys/class/gpio/export",
[o_wronly,o_cloexec], 0),
case alcove:write(Drv, FD, integer_to_list(Pin)) of
case alcove:write(Drv, [], FD, integer_to_list(Pin)) of
{ok, _} -> ok;
{error,ebusy} -> ok
end,
alcove:close(Drv, FD).
alcove:close(Drv, [], FD).

View File

@@ -21,7 +21,7 @@
start() ->
{ok, Drv} = alcove_drv:start_link([{exec, "sudo"}]),
case alcove_cgroup:supported(Drv) of
case alcove_cgroup:supported(Drv, []) of
true ->
ok = alcove_cgroup:create(Drv, [], [<<"alcove">>]),
{ok,1} = alcove_cgroup:set(Drv, [], <<"cpuset">>, [<<"alcove">>],
@@ -43,7 +43,7 @@ sandbox(Drv) ->
sandbox(Drv, Argv) ->
{Path, Arg0, Args} = argv(Argv),
{ok, Child} = alcove:clone(Drv, [
{ok, Child} = alcove:clone(Drv, [], [
clone_newipc,
clone_newnet,
clone_newns,

View File

@@ -22,7 +22,7 @@ start() ->
start(Options) ->
{ok, Drv} = alcove_drv:start_link(Options ++ [{exec, "sudo"}]),
ok = alcove:chdir(Drv, "/"),
ok = alcove:chdir(Drv, [], "/"),
chroot_init(),
cgroup_init(Drv,
[<<"alcove">>],
@@ -130,7 +130,7 @@ network_drain(Drv, Socket, Child) ->
end.
clone(Drv, _Options) ->
alcove:clone(Drv, [
alcove:clone(Drv, [], [
clone_newipc,
clone_newnet,
clone_newns,
@@ -142,7 +142,7 @@ clone_init(Drv, Child, Options) ->
Id = id(),
Hostname = lists:concat(["alcove", Child]),
case alcove_cgroup:supported(Drv) of
case alcove_cgroup:supported(Drv, []) of
true ->
cgroup_init(Drv, [<<"alcove">>, Hostname], Options),
{ok,_} = alcove_cgroup:set(Drv, [], <<>>, [<<"alcove">>, Hostname],
@@ -309,7 +309,7 @@ cgroup_init(Drv, Namespace, Options) ->
Bytes = proplists:get_value(<<"memory.limit_in_bytes">>,
Options, <<"16m">>),
case alcove_cgroup:supported(Drv) of
case alcove_cgroup:supported(Drv, []) of
true ->
alcove_cgroup:create(Drv, [], Namespace),
alcove_cgroup:set(Drv, [], <<"cpuset">>, Namespace,

View File

@@ -43,9 +43,9 @@ accept(LSock, Options) ->
create(Socket, _Options) ->
{ok, Drv} = alcove_drv:start_link([{exec,"sudo"}]),
ok = alcove:chdir(Drv, "/"),
ok = alcove:chdir(Drv, [], "/"),
{ok, PID} = alcove:clone(Drv, [
{ok, PID} = alcove:clone(Drv, [], [
clone_newipc,
clone_newnet,
clone_newns,

View File

@@ -15,6 +15,7 @@
{xref_checks, [undefined_function_calls]}.
{eunit_opts, [verbose, {report, {eunit_surefire, [{dir, "."}]}}]}.
%{dialyzer, [{plt_extra_apps, ["examples","test"]}]}.
% rebar2 compatibility: disable port compiler
{port_specs, [{"", []}]}.

View File

@@ -1,7 +1,7 @@
{application, alcove,
[
{description, "Erlang application container/sandbox"},
{vsn, "0.20.0"},
{vsn, "0.21.0"},
{registered, []},
{applications, [
kernel,

View File

@@ -14,18 +14,14 @@
-module(alcove_cgroup).
-include_lib("alcove/include/alcove.hrl").
-export([supported/1, supported/2]).
-export([create/1, create/2, create/3, destroy/1, destroy/2, destroy/3]).
-export([supported/2]).
-export([create/2, create/3, destroy/2, destroy/3]).
-export([cgroup/1, cgroup/2, fold/5, fold/6, fold_files/6, fold_files/7]).
-export([get/5, set/6]).
-export([is_file/3, is_dir/3]).
-export([mounts/1, mounts/2]).
-export([join/2,relpath/1,expand/1]).
-spec supported(alcove_drv:ref()) -> boolean().
supported(Drv) ->
supported(Drv, []).
-spec supported(alcove_drv:ref(),alcove:fork_path()) -> boolean().
supported(Drv, Pids) ->
foreach([
@@ -50,10 +46,6 @@ supported(Drv, Pids) ->
%% * the process may be running in a chroot or a different mount namespace
%%
-spec create(alcove_drv:ref()) -> 'ok'.
create(Drv) ->
create(Drv, []).
-spec create(alcove_drv:ref(),alcove:fork_path()) -> 'ok'.
create(Drv, Pids) ->
create(Drv, Pids, [<<"alcove">>]).
@@ -74,10 +66,6 @@ create_1(Drv, Pids, Namespace) ->
end,
fold(Drv, <<>>, [], Fun, []).
-spec destroy(alcove_drv:ref()) -> [ok | {error, file:posix()}].
destroy(Drv) ->
destroy(Drv, []).
-spec destroy(alcove_drv:ref(),alcove:fork_path()) -> [ok | {error, file:posix()}].
destroy(Drv, Pids) ->
destroy(Drv, Pids, [<<"alcove">>]).
@@ -228,7 +216,7 @@ is_dir(Drv, Pids, Path) ->
is_file(Drv, Pids, File) ->
case alcove:open(Drv, Pids, File, [o_rdonly], 0) of
{ok, FH} ->
alcove:close(Drv, FH),
alcove:close(Drv, Pids, FH),
true;
_ ->
false

View File

@@ -55,21 +55,21 @@ start() ->
#state{
pid = Drv,
seccomp = alcove:define(Drv, seccomp_mode_filter) =/= unknown
seccomp = alcove:define(Drv, [], seccomp_mode_filter) =/= unknown
}.
stop(#state{pid = Drv}) ->
alcove_drv:stop(Drv).
kill(#state{pid = Drv}) ->
{ok, Pid} = alcove:fork(Drv),
{ok, Pid} = alcove:fork(Drv, []),
enforce(Drv, [Pid], ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_KILL)),
% Allowed: cached by process
Reply0 = alcove:getpid(Drv, [Pid]),
% Not allowed: SIGSYS
Reply1 = (catch alcove:getcwd(Drv, [Pid])),
Reply2 = alcove:kill(Drv, Pid, 0),
Reply2 = alcove:kill(Drv, [], Pid, 0),
[
?_assertEqual(Pid, Reply0),
@@ -78,11 +78,11 @@ kill(#state{pid = Drv}) ->
].
allow(#state{pid = Drv}) ->
{ok, Pid} = alcove:fork(Drv),
{ok, Pid} = alcove:fork(Drv, []),
enforce(Drv, [Pid], ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_ALLOW)),
Reply0 = alcove:getpid(Drv, [Pid]),
Reply1 = alcove:getcwd(Drv, [Pid]),
Reply2 = alcove:kill(Drv, Pid, 0),
Reply2 = alcove:kill(Drv, [], Pid, 0),
alcove:exit(Drv, [Pid], 0),
[
@@ -92,7 +92,7 @@ allow(#state{pid = Drv}) ->
].
trap(#state{pid = Drv}) ->
{ok, Pid} = alcove:fork(Drv),
{ok, Pid} = alcove:fork(Drv, []),
ok = alcove:sigaction(Drv, [Pid], sigsys, sig_catch),
enforce(Drv, [Pid], ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_TRAP)),
@@ -111,7 +111,7 @@ trap(#state{pid = Drv}) ->
ok
end,
Reply3 = alcove:kill(Drv, Pid, 0),
Reply3 = alcove:kill(Drv, [], Pid, 0),
alcove:exit(Drv, [Pid], 0),
[
@@ -122,13 +122,13 @@ trap(#state{pid = Drv}) ->
].
allow_syscall(Drv, Syscall) ->
case alcove:define(Drv, Syscall) of
case alcove:define(Drv, [], Syscall) of
unknown -> [];
NR -> ?ALLOW_SYSCALL(NR)
end.
filter(Drv) ->
Arch = alcove:define(Drv, alcove:audit_arch()),
Arch = alcove:define(Drv, [], alcove:audit_arch()),
[
?VALIDATE_ARCHITECTURE(Arch),
?EXAMINE_SYSCALL,

View File

@@ -83,12 +83,12 @@ start() ->
{ok, Drv} = alcove_drv:start_link([{exec, Exec}, {maxchild, 8}]),
ok = alcove:sigaction(Drv, sigchld, sig_catch),
ok = alcove:sigaction(Drv, sigpipe, sig_ign),
ok = alcove:sigaction(Drv, [], sigchld, sig_catch),
ok = alcove:sigaction(Drv, [], sigpipe, sig_ign),
case {Use_fork, os:type()} of
{false, {unix,linux} = OS} ->
{ok, Child} = alcove:clone(Drv, [
{ok, Child} = alcove:clone(Drv, [], [
clone_newipc,
clone_newnet,
clone_newns,
@@ -102,7 +102,7 @@ start() ->
os = OS
};
{_, {unix,_} = OS} ->
{ok, Child} = alcove:fork(Drv),
{ok, Child} = alcove:fork(Drv, []),
#state{
pid = Drv,
child = Child,
@@ -130,7 +130,7 @@ msg(_) ->
).
version(#state{pid = Drv}) ->
Version = alcove:version(Drv),
Version = alcove:version(Drv, []),
?_assertEqual(true, is_binary(Version)).
iodata(#state{pid = Drv}) ->
@@ -141,18 +141,18 @@ iodata(#state{pid = Drv}) ->
21,
<<22>>],
Reply0 = alcove:iolist_to_bin(Drv, Iolist),
Reply0 = alcove:iolist_to_bin(Drv, [], Iolist),
% Valid iolists: binary, string, lists, bytes must be within a list
Reply1 = (catch alcove:iolist_to_bin(Drv, 10)),
Reply2 = (catch alcove:iolist_to_bin(Drv, [123456])),
Reply3 = alcove:iolist_to_bin(Drv, <<1,2,3,4,5,6>>),
Reply4 = alcove:iolist_to_bin(Drv, "ok"),
Reply1 = (catch alcove:iolist_to_bin(Drv, [], 10)),
Reply2 = (catch alcove:iolist_to_bin(Drv, [], [123456])),
Reply3 = alcove:iolist_to_bin(Drv, [], <<1,2,3,4,5,6>>),
Reply4 = alcove:iolist_to_bin(Drv, [], "ok"),
% Arbitrary implementation limit of 16 nested
% lists. iolist_to_binary/1 does not have this limitation.
Reply5 = alcove:iolist_to_bin(Drv, [[[[[[[[[[[[[[[["ok"]]]]]]]]]]]]]]]]),
Reply6 = (catch alcove:iolist_to_bin(Drv, [[[[[[[[[[[[[[[[["fail"]]]]]]]]]]]]]]]]])),
Reply5 = alcove:iolist_to_bin(Drv, [], [[[[[[[[[[[[[[[["ok"]]]]]]]]]]]]]]]]),
Reply6 = (catch alcove:iolist_to_bin(Drv, [], [[[[[[[[[[[[[[[[["fail"]]]]]]]]]]]]]]]]])),
[
?_assertEqual(Reply0, iolist_to_binary(Iolist)),
@@ -165,7 +165,7 @@ iodata(#state{pid = Drv}) ->
].
pid(#state{pid = Drv}) ->
Pids = alcove:pid(Drv),
Pids = alcove:pid(Drv, []),
?_assertEqual(1, length(Pids)).
getpid(#state{clone = true, pid = Drv, child = Child}) ->
@@ -177,7 +177,7 @@ getpid(#state{pid = Drv, child = Child}) ->
?_assertEqual(true, PID > 0).
setopt(#state{pid = Drv}) ->
{ok, Fork} = alcove:fork(Drv),
{ok, Fork} = alcove:fork(Drv, []),
true = alcove:setopt(Drv, [Fork], maxchild, 128),
@@ -208,7 +208,7 @@ setopt(#state{pid = Drv}) ->
].
event(#state{pid = Drv}) ->
{ok, Fork} = alcove:fork(Drv),
{ok, Fork} = alcove:fork(Drv, []),
Reply0 = alcove:exit(Drv, [Fork], 0),
Reply1 = alcove:event(Drv, [Fork], 5000),
Reply2 = alcove:event(Drv, [], 5000),
@@ -262,7 +262,7 @@ clone_define(_) ->
[].
setns(#state{clone = true, pid = Drv, child = Child}) ->
{ok, Child1} = alcove:fork(Drv),
{ok, Child1} = alcove:fork(Drv, []),
ok = alcove:setns(Drv, [Child1], [
"/proc/",
integer_to_list(Child),
@@ -275,25 +275,25 @@ setns(_) ->
[].
unshare(#state{clone = true, pid = Drv}) ->
Host = alcove:gethostname(Drv),
{ok, Child1} = alcove:fork(Drv),
Host = alcove:gethostname(Drv, []),
{ok, Child1} = alcove:fork(Drv, []),
ok = alcove:unshare(Drv, [Child1], [clone_newuts]),
Reply = alcove:sethostname(Drv, [Child1], "unshare"),
Hostname = alcove:gethostname(Drv, [Child1]),
Host = alcove:gethostname(Drv),
Host = alcove:gethostname(Drv, []),
[?_assertEqual(ok, Reply),
?_assertEqual({ok, <<"unshare">>}, Hostname)];
unshare(_) ->
[].
mount_define(#state{os = {unix,sunos}, pid = Drv}) ->
Flags = alcove:define(Drv, [
Flags = alcove:define(Drv, [], [
rdonly,
nosuid
]),
?_assertEqual(true, is_integer(Flags));
mount_define(#state{pid = Drv}) ->
Flags = alcove:define(Drv, [
Flags = alcove:define(Drv, [], [
rdonly,
nosuid,
noexec,
@@ -414,7 +414,7 @@ fork(#state{pid = Drv, child = Child}) ->
].
badpid(#state{pid = Drv}) ->
{ok, Child} = alcove:fork(Drv),
{ok, Child} = alcove:fork(Drv, []),
% EPIPE or PID not found
ok = alcove:execvp(Drv, [Child], "/bin/sh",
@@ -439,17 +439,17 @@ badpid(#state{pid = Drv}) ->
].
signal(#state{pid = Drv}) ->
{ok, Child1} = alcove:fork(Drv),
{ok, Child1} = alcove:fork(Drv, []),
SA0 = alcove:sigaction(Drv, [Child1], sigterm, sig_ign),
Kill0 = alcove:kill(Drv, Child1, sigterm),
Kill0 = alcove:kill(Drv, [], Child1, sigterm),
Pid0 = alcove:getpid(Drv, [Child1]),
SA1 = alcove:sigaction(Drv, [Child1], sigterm, sig_dfl),
Kill1 = alcove:kill(Drv, Child1, sigterm),
Kill1 = alcove:kill(Drv, [], Child1, sigterm),
waitpid(Drv, [], Child1),
alcove:kill(Drv, Child1, 0),
Search = alcove:kill(Drv, Child1, 0),
alcove:kill(Drv, [], Child1, 0),
Search = alcove:kill(Drv, [], Child1, 0),
[
?_assertEqual(ok, SA0),
@@ -470,12 +470,12 @@ portstress(#state{pid = Drv, child = Child}) ->
?_assertEqual(Ok, Reply).
forkstress(#state{pid = Drv}) ->
{ok, Fork} = alcove:fork(Drv),
{ok, Fork} = alcove:fork(Drv, []),
Reply = forkstress_1(Drv, Fork, 100),
?_assertEqual(ok, Reply).
forkchain(#state{pid = Drv}) ->
{ok, Child0} = alcove:fork(Drv),
{ok, Child0} = alcove:fork(Drv, []),
{ok, Child1} = alcove:fork(Drv, [Child0]),
{ok, Child2} = alcove:fork(Drv, [Child0, Child1]),
{ok, Child3} = alcove:fork(Drv, [Child0, Child1, Child2]),
@@ -488,7 +488,7 @@ forkchain(#state{pid = Drv}) ->
?_assertEqual(Pid, Child4).
eof(#state{pid = Drv}) ->
{ok, Child} = alcove:fork(Drv),
{ok, Child} = alcove:fork(Drv, []),
{ok, Child0} = alcove:fork(Drv, [Child]),
ok = alcove:eof(Drv, [Child,Child0], stderr),
@@ -513,7 +513,7 @@ eof(#state{pid = Drv}) ->
].
alloc(#state{os = {unix,_}, pid = Drv}) ->
{ok, Buf, Cstruct} = alcove:alloc(Drv,
{ok, Buf, Cstruct} = alcove:alloc(Drv, [],
[<<1,2,3,4,5,6,7,8,9,10>>,
{ptr, 11},
<<11,12,13,14,15>>,
@@ -532,7 +532,7 @@ alloc(#state{os = {unix,_}, pid = Drv}) ->
].
prctl(#state{os = {unix,linux}, pid = Drv}) ->
{ok, Fork} = alcove:fork(Drv),
{ok, Fork} = alcove:fork(Drv, []),
% capability is set:
% returns 0 | 1 in function result, arg2 = int
@@ -565,7 +565,7 @@ prctl(_) ->
[].
priority(#state{os = {unix,_}, pid = Drv}) ->
{ok, Fork0} = alcove:fork(Drv),
{ok, Fork0} = alcove:fork(Drv, []),
{ok, Fork1} = alcove:fork(Drv, [Fork0]),
{ok, Fork2} = alcove:fork(Drv, [Fork0]),
@@ -614,7 +614,7 @@ execvp(_) ->
[].
execvp_with_signal(#state{pid = Drv}) ->
{ok, Fork} = alcove:fork(Drv),
{ok, Fork} = alcove:fork(Drv, []),
Reply0 = (catch alcove:execvp(Drv, [Fork], "/bin/sh",
["/bin/sh", "-c", "kill -9 $$"])),
Reply1 = alcove:event(Drv, [Fork], 5000),
@@ -657,8 +657,8 @@ stderr(_) ->
[].
execve(#state{pid = Drv}) ->
{ok, Child0} = alcove:fork(Drv),
{ok, Child1} = alcove:fork(Drv),
{ok, Child0} = alcove:fork(Drv, []),
{ok, Child1} = alcove:fork(Drv, []),
Reply0 = (catch alcove:execve(Drv, [Child0], "/usr/bin/env",
["/usr/bin/env"], ["A=1", "B=2", "C=3", false])),
@@ -694,13 +694,13 @@ stream(#state{pid = Drv}) ->
?_assertEqual(ok, Reply).
open(#state{pid = Drv}) ->
O_RDONLY = alcove:define(Drv, o_rdonly),
O_RDONLY = alcove:define(Drv, [], o_rdonly),
File = "/nonexistent",
Reply0 = alcove:open(Drv, File, O_RDONLY, 0),
Reply1 = alcove:open(Drv, File, [O_RDONLY,O_RDONLY,O_RDONLY,O_RDONLY], 0),
Reply2 = alcove:open(Drv, File, [o_rdonly, o_rdonly, o_rdonly], 0),
Reply0 = alcove:open(Drv, [], File, O_RDONLY, 0),
Reply1 = alcove:open(Drv, [], File, [O_RDONLY,O_RDONLY,O_RDONLY,O_RDONLY], 0),
Reply2 = alcove:open(Drv, [], File, [o_rdonly, o_rdonly, o_rdonly], 0),
[
?_assertEqual({error,enoent}, Reply0),
@@ -716,7 +716,7 @@ execvp_mid_chain(#state{os = {unix,OS}, pid = Drv}) ->
alcove:stdin(Drv, Pids, "test\n"),
Reply0 = alcove:stdout(Drv, Pids, 5000),
waitpid_exit(Drv, [], lists:last(Rest)),
Reply1 = [ alcove:kill(Drv, Pid, 0) || Pid <- Rest ],
Reply1 = [ alcove:kill(Drv, [], Pid, 0) || Pid <- Rest ],
ChildState = case OS of
openbsd -> {error,esrch};
@@ -772,7 +772,7 @@ flush(stdout, Drv, Pids) ->
get_unused_pid(Drv) ->
PID = crypto:rand_uniform(16#0affffff, 16#0fffffff),
case alcove:kill(Drv, PID, 0) of
case alcove:kill(Drv, [], PID, 0) of
{error,esrch} -> PID;
_ -> get_unused_pid(Drv)
end.