View Source prx (prx v0.16.3)

Link to this section Summary

Functions

Register a function to be called at task termination.

Make a synchronous call into the port driver

cap_enter(2): place process into capability mode

cap_fcntls_get(2): get allowed fcntl commands in capability mode

cap_fcntls_limit(2): manage fcntl commands in capability mode

cap_getmode(2): check if capability mode is enabled

cap_ioctls_limit(2): manage allowed ioctl commands

cap_rights_limit(2): manage process capabilities

chdir(2): change process current working directory

chmod(2): change file permissions

chown(2): change file ownership

chroot(2): change root directory

clearenv(3): zero process environment

clone(2): create a new process

close(2): close a file descriptor

Assign a new process owner

Returns the list of child PIDs for this process.

Retrieve process info for forked processes

Get the gen_server PID for the task

environ(7): return the process environment variables

Close stdin of a task

Close task standard I/O file descriptor

Close stdin, stdout or stderr of child process.

See also: eof/2.

Test if the task has called exec(2)

execve(2): replace process image with environment

execve(2): replace process image with environment

execvp(2): replace the current process image using the search path

execvp(2): replace the current process image using the search path

exit(3): cause an prx control process to exit

fcntl(2) : perform operation on a file descriptor

See also: fcntl/4.

fcntl(2): perform operations on a file descriptor with argument

fexecve(2): replace the process image

filter/2 : restrict control process calls

filter/3 : restrict control process and subprocess calls

fork(2): create a new system process

fork(2): create a child process

Get control process attributes

Get control process attributes

getcwd(3): return the current working directory

getenv(3): retrieve an environment variable

getgid(2): retrieve the process group ID

getgroups(2): retrieve the list of supplementary groups

gethostname(2): retrieve the system hostname

Retrieve port options for event loop

getpgrp(2): retrieve the process group

getpid(2): retrieve the system PID of the process

getpriority(2): retrieve scheduling priority of process, process group or user

getresgid(2): get real, effective and saved group ID

getresuid(2): get real, effective and saved user ID

getrlimit(2): retrieve the resource limits for a process

getsid(2): retrieve the session ID

getuid(2): returns the process user ID

ioctl(2) : control device

jail(2): restrict the current process in a system jail

kill(2): terminate a process

lseek(2): set file offset for read/write

mkdir(2) : create a directory
mkfifo(3) : create a named pipe

mount(2) : mount a filesystem, Linux style

(Solaris) mount(2) : mount a filesystem

open(2): returns a file descriptor associated with a file

open(2) : open a file specifying permissions

Get the parent PID for the task

Retrieves the system PID of the process similar to getpid(2)

Get the process pipeline list for the task

pivot_root(2): change the root mount

pledge(2): restrict system operations

prctl(2) : operations on a process

procctl(2): control processes

ptrace(2): process trace

read(2): read bytes from a file descriptor

readdir(3): retrieve list of objects in a directory

Fork+exec prx process.

Replace the port process image using execve(2)/fexecve(2).

Equivalent to reexec / 1.

Equivalent to reexec / 3.

rmdir(2): delete a directory

seccomp(2) : restrict system operations

select(2): poll a list of file descriptor for events

setcpid() : Set options for child process of prx control process

setcpid() : Set options for child process of prx control process

setenv(3): set an environment variable

setgid(2): set the GID of the process

setgroups(2): set the supplementary groups of the process

sethostname(2): set the system hostname

setns(2): attach to a namespace

(Linux) setns(2) : attach to a namespace, specifying namespace type

Set port options

setpgid(2): set process group

setpriority(2): set scheduling priority of process, process group or user

setproctitle(3): set the process title

setresgid(2): set real, effective and saved group ID

setresuid(2): set real, effective and saved user ID

setrlimit(2): set a resource limit

setsid(2): create a new session

setuid(2): change UID

sigaction(2): set process behaviour for signals

socket(2): returns a file descriptor for a communication endpoint

Send data to the standard input of the process

Assign a process to receive stdio

Terminate the task

Convenience function to fork a privileged process in the shell.

Convenience function to fork a privileged process in the shell.

Fork a subprocess and run a sequence of operations

Create a subprocess and run a sequence of operations using optional function calls

umount2(2) : unmount a filesystem

umount(2): unmount a filesystem

unlink(2): delete a name from the filesystem

unsetenv(3): remove an environment variable

unshare(2): create a new namespace in the current process

unveil(2): restrict filesystem view

waitpid(2): wait for process to change state

write(2): write to a file descriptor

Link to this section Types

-type call() :: alcove_proto:call() | reexec | replace_process_image | getcpid.
-type constant() :: atom() | integer().
-type cpid() ::
    #{pid := pid_t(),
      flowcontrol := uint32_t(),
      signaloneof := uint32_t(),
      exec := boolean(),
      fdctl := fd(),
      stdin := fd(),
      stdout := fd(),
      stderr := fd()}.
-type cstruct() :: [binary() | {ptr, binary() | non_neg_integer()}, ...].
-type fd() :: int32_t().
-type gid_t() :: uint32_t().
-type int32_t() :: - 2147483647..2147483647.
-type int64_t() :: - 9223372036854775807..9223372036854775807.
-type mode_t() :: uint32_t().
-type off_t() :: uint64_t().
-type pid_t() :: int32_t().
-type posix() :: alcove:posix().
-type prx_opt() :: maxchild | exit_status | maxforkdepth | termsig | flowcontrol | signaloneof.
-type ptr_arg() :: binary() | constant() | cstruct().
-type ptr_val() :: binary() | integer() | cstruct().
-type size_t() :: uint64_t().
-type ssize_t() :: int64_t().
-type task() :: pid().
-type uid_t() :: uint32_t().
-type uint32_t() :: 0..4294967295.
-type uint64_t() :: 0..18446744073709551615.
-type waitstatus() :: {exit_status, int32_t()} | {termsig, atom()} | {stopsig, atom()} | continued.

Link to this section Functions

-spec atexit(task(), fun((pid(), [pid_t()], cpid()) -> any())) -> ok.

Register a function to be called at task termination.

The atexit function runs in the parent of the process. atexit/2 must use prx_drv:call/4 to manipulate the task.

examples

Examples

The default function closes stdin, stdout and stderr of the system process:

  fun(Drv, Pipeline, Pid) ->
   prx_drv:call(Drv, Pipeline, close, [maps:get(stdout, Pid)]),
   prx_drv:call(Drv, Pipeline, close, [maps:get(stdin, Pid)]),
   prx_drv:call(Drv, Pipeline, close, [maps:get(stderr, Pid)])
  end
-spec call(task(), call(), [any()]) -> any().

Make a synchronous call into the port driver

The list of available calls and their arguments can be found here:

https://hexdocs.pm/alcove/alcove.html#functions

For example, to directly call alcove:execve/5:

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> prx:call(Task, execve, ["/bin/ls", ["/bin/ls", "-al"], ["HOME=/home/foo"]]).
  ok
-spec cap_enter(task()) -> ok | {error, posix()}.

cap_enter(2): place process into capability mode

support

Support

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.158.0>}
  3> prx:cap_enter(Task1).
  ok
  4> prx:kill(Task1, 0, 0).
  {error,ecapmode}
  5> prx:kill(Task, 0, 0).
  ok
Link to this function

cap_fcntls_get(Task, FD)

View Source
-spec cap_fcntls_get(task(), fd()) -> {ok, int32_t()} | {error, posix()}.

cap_fcntls_get(2): get allowed fcntl commands in capability mode

support

Support

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.165.0>}
  3> {ok, FD} = prx:open(Task1, "/etc/passwd", [o_rdonly]).
  {ok,7}
  4> prx:cap_enter(Task1).
  ok
  5> prx:cap_fcntls_get(Task1, FD).
  {ok,120}
Link to this function

cap_fcntls_limit(Task, FD, Rights)

View Source
-spec cap_fcntls_limit(task(), fd(), [constant()]) -> ok | {error, posix()}.

cap_fcntls_limit(2): manage fcntl commands in capability mode

support

Support

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.165.0>}
  3> {ok, FD} = prx:open(Task1, "/etc/passwd", [o_rdonly]).
  {ok,7}
  4> prx:cap_enter(Task1).
  ok
  5> prx:cap_fcntls_get(Task1, FD).
  {ok,120}
  6> prx:cap_fcntls_limit(Task1, FD, [cap_fcntl_setfl]).
  ok
  7> prx:cap_fcntls_get(Task1, FD).
  {ok,16}
-spec cap_getmode(task()) -> {ok, 0 | 1} | {error, posix()}.

cap_getmode(2): check if capability mode is enabled

0 : false

1 : true

support

Support

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.165.0>}
  3> prx:cap_enter(Task1).
  ok
  4> prx:cap_getmode(Task).
  {ok,0}
  5> prx:cap_getmode(Task1).
  {ok,1}
Link to this function

cap_ioctls_limit(Task, FD, Rights)

View Source
-spec cap_ioctls_limit(task(), fd(), [constant()]) -> ok | {error, posix()}.

cap_ioctls_limit(2): manage allowed ioctl commands

support

Support

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.158.0>}
  3> {ok, FD} = prx:open(Task1, "/dev/pts/1", [o_rdwr, o_nonblock]).
  {ok,7}
  4> prx:cap_enter(Task1).
  ok
  5> prx:cap_ioctls_limit(Task1, FD, [tiocmget, tiocgwinsz]).
  ok
  6> prx:ioctl(Task1, FD, tiocmset, <<>>).
  {error,enotcapable}
  7> prx:ioctl(Task1, FD, tiocmget, <<>>).
  {ok,#{arg => <<>>,return_value => 0}}
Link to this function

cap_rights_limit(Task, FD, Rights)

View Source
-spec cap_rights_limit(task(), fd(), [constant()]) -> ok | {error, posix()}.

cap_rights_limit(2): manage process capabilities

support

Support

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.168.0>}
  3> {ok, FD} = prx:open(Task1, "/etc/passwd", [o_rdonly]).
  {ok,7}
  4> prx:cap_enter(Task1).
  ok
  5> prx:cap_rights_limit(Task1, FD, [cap_read]).
  ok
  6> prx:read(Task1, FD, 64).
  {ok,<<"# $FreeBSD$\n#\nroot:*:0:0:Charlie &:/root:/bin/csh\ntoor:*:0:0:Bou">>}
  7> prx:lseek(Task1, FD, 0, 0).
  {error,enotcapable}
  8> prx:open(Task1, "/etc/passwd", [o_rdonly]).
  {error,ecapmode}
-spec chdir(task(), iodata()) -> ok | {error, posix()}.

chdir(2): change process current working directory

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.178.0>}
  3> prx:chdir(Task, "/").
  ok
  4> prx:chdir(Task1, "/tmp").
  ok
  5> prx:getcwd(Task).
  {ok,<<"/">>}
  6> prx:getcwd(Task1).
  {ok,<<"/tmp">>}
-spec chmod(task(), iodata(), mode_t()) -> ok | {error, posix()}.

chmod(2): change file permissions

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.178.0>}
  3> {ok, FD} = prx:open(Task1, "/tmp/testfile.txt", [o_wronly, o_creat], 8#644).
  {ok,7}
  4> prx:chmod(Task1, "/tmp/testfile.txt", 8#400).
  ok
Link to this function

chown(Task, Path, Owner, Group)

View Source
-spec chown(task(), iodata(), uid_t(), gid_t()) -> ok | {error, posix()}.

chown(2): change file ownership

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.155.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.159.0>}
  4> {ok, FD} = prx:open(Task1, "/tmp/testfile.txt", [o_wronly, o_creat], 8#644).
  {ok,7}
  5> prx:chown(Task1, "/tmp/testfile.txt", 0, 0).
  ok
-spec chroot(task(), iodata()) -> ok | {error, posix()}.

chroot(2): change root directory

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.155.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.159.0>}
  4> prx:chroot(Task1, "/tmp").
  ok
  5> prx:chdir(Task1, "/").
  ok
  6> prx:getcwd(Task1).
  {ok,<<"/">>}
-spec clearenv(task()) -> ok | {error, posix()}.

clearenv(3): zero process environment

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.155.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.159.0>}
  3> prx:clearenv(Task1).
  ok
  4> prx:environ(Task1).
  []
-spec clone(task(), Flags :: [constant()]) -> {ok, task()} | {error, posix()}.

clone(2): create a new process

support

Support

• Linux

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  3> {ok, Task1} = prx:clone(Task, [clone_newns, clone_newpid, clone_newipc, clone_newuts, clone_newnet]).
  {ok,<0.184.0>}
  4> prx:getpid(Task1).
  1
-spec close(task(), fd()) -> ok | {error, posix()}.

close(2): close a file descriptor

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.178.0>}
  3> {ok, FD} = prx:open(Task1, "/tmp/testfile.txt", [o_wronly, o_creat], 8#644).
  {ok,7}
  4> prx:close(Task1, FD).
  ok
-spec cmd(task(), [iodata()]) -> binary() | {error, posix()}.
Link to this function

controlling_process(Task, Pid)

View Source
-spec controlling_process(task(), pid()) -> ok | {error, badarg}.

Assign a new process owner

call mode: the controlling process is allowed to make calls to the prx process.

exec mode: the controlling process receives standard output and standard error from the prx process
-spec cpid(task()) -> [cpid()].

Returns the list of child PIDs for this process.

Each child task is a map composed of:

• pid: system pid

• exec: true if the child has called exec()

• fdctl: parent end of CLOEXEC file descriptor used to monitor if the child process has called exec()

• stdin: parent end of the child process' standard input

• stdout: parent end of the child process' standard output

• stderr: parent end of the child process' standard error

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.182.0>}
  3> {ok, Task2} = prx:fork(Task).
  {ok,<0.184.0>}
  4> prx:cpid(Task).
  [#{exec => true,fdctl => -2,flowcontrol => -1,pid => 27809,
     signaloneof => 15,stderr => 13,stdin => 10,stdout => 11},
   #{exec => false,fdctl => 9,flowcontrol => -1,pid => 27810,
     signaloneof => 15,stderr => 17,stdin => 14,stdout => 15}]
-spec cpid(task(), task() | pid_t()) -> cpid() | error.

Retrieve process info for forked processes

Retrieve the map for a child process as returned in prx:cpid/1.

cpid/2 searches the list of a process' children for a PID (an erlang or a system PID) and returns a map containing the parent's file descriptors towards the child.

See also: cpid/1.

-spec drv(task()) -> pid().

Get the gen_server PID for the task

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  <0.181.0>
-spec environ(task()) -> [binary()].

environ(7): return the process environment variables

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> prx:environ(Task).
  [<<"LANG=C.UTF-8">>,
   <<"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin">>,
   <<"TERM=screen">>, <<"SHELL=/bin/bash">>]
-spec eof(task()) -> ok | {error, posix()}.

Close stdin of a task

Close the task standard input by sending a request to the parent. The operation may fail if the parent/child are associated with different erlang processes.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.200.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.204.0>}
  3> prx:execvp(Task1, ["cat"]).
  ok
  4> prx:eof(Task1).
  ok
  5> flush().
  Shell got {exit_status,<0.204.0>,0}
  ok
-spec eof(task(), task() | pid_t() | stdin | stdout | stderr) -> ok | {error, posix()}.

Close task standard I/O file descriptor

Close stdin, stdout or stderr for a task.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.176.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.211.0>}
  3> prx:execvp(Task1, ["cat"]).
  ok
  4> prx:eof(Task1, stdout).
  ok
  5> flush().
  Shell got {exit_status,<0.211.0>,0}
  ok
-spec eof(task(), task() | pid_t(), stdin | stdout | stderr) -> ok | {error, posix()}.
Close stdin, stdout or stderr of child process.

See also: eof/2.

-spec execed(task()) -> boolean().

Test if the task has called exec(2)

Returns true if the task is running in exec mode.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.182.0>}
  3> prx:execed(Task1).
  false
  4> prx:execvp(Task1, ["cat"]).
  ok
  5> prx:execed(Task1).
  true
-spec execve(task(), [iodata()], [iodata()]) -> ok | {error, posix()}.

execve(2): replace process image with environment

Replace the process image, specifying the environment for the new process image.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> prx:execvp(Task, "cat", ["name-in-process-list", "-n"])
  ok
Link to this function

execve(Task, Arg0, Argv, Env)

View Source
-spec execve(task(), iodata(), [iodata()], [iodata()]) -> ok | {error, posix()}.

execve(2): replace process image with environment

Replace the process image, specifying the environment for the new process image.

examples

Examples

Set the command name in the process list:

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> prx:execve(Task, "/bin/cat", ["name-in-process-list", "-n"], ["VAR=1"]).
  ok
-spec execvp(task(), [iodata()]) -> ok | {error, posix()}.

execvp(2): replace the current process image using the search path

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.194.0>}
  3> prx:execvp(Task1, ["cat", "-n"]).
  ok
  4> prx:stdin(Task1, <<"test\n">>).
  ok
  5> flush().
  Shell got {stdout,<0.194.0>,<<"     1\ttest\n">>}
  ok
Link to this function

execvp(Task, Arg0, Argv)

View Source
-spec execvp(task(), iodata(), [iodata()]) -> ok | {error, posix()}.

execvp(2): replace the current process image using the search path

examples

Examples

Set the command name in the process list:

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> prx:execvp(Task, "cat", ["name-in-process-list", "-n"])
  ok
-spec exit(task(), int32_t()) -> ok.

exit(3): cause an prx control process to exit

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.178.0>}
  3> prx:exit(Task1, 111).
  ok
  4> flush().
  Shell got {exit_status,<0.159.0>,111}
  ok
-spec fcntl(task(), fd(), constant()) -> {ok, int64_t()} | {error, posix()}.
fcntl(2) : perform operation on a file descriptor

See also: fcntl/4.

Link to this function

fcntl(Task, FD, Cmd, Arg)

View Source
-spec fcntl(task(), fd(), constant(), int64_t()) -> {ok, int64_t()} | {error, posix()}.

fcntl(2): perform operations on a file descriptor with argument

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> Stdin = 0.
  0
  3> prx:fcntl(Task, Stdin, f_getfd, 0).
  {ok,0}
Link to this function

fexecve(Task, FD, Argv, Env)

View Source
-spec fexecve(task(), int32_t(), [iodata()], [iodata()]) -> ok | {error, posix()}.

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, FD} = prx:open(Task, "/bin/ls", [o_rdonly,o_cloexec]),
  ok = prx:fexecve(Task, FD, ["-al"], ["FOO=123"]).

Linux requires an environment to be set unlike with execve(2). The environment can be empty:

  % Environment required on Linux
  ok = prx:fexecve(Task, FD, ["ls", "-al"], [""]).

support

Support

• Linux

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.184.0>}
  3> {ok, FD} = prx:open(Task1, "/usr/bin/env", [o_rdonly,o_cloexec], 0).
  {ok,7}
  4> prx:fexecve(Task1, FD, ["env", "-0"], ["FOO=123"]).
  ok
  5> flush().
  Shell got {stdout,<0.208.0>,<<70,79,79,61,49,50,51,0>>}
  Shell got {exit_status,<0.208.0>,0}
  ok
-spec filter(task(), [call()] | {allow, [call()]} | {deny, [call()]}) -> ok.

filter/2 : restrict control process calls

Restricts the set of calls available to a prx control process. If fork is allowed, any subsequently forked control processes inherit the set of filtered calls:

  {ok, Ctrl} = prx:fork(),
  ok = prx:filter(Ctrl, [getpid]),
  {ok, Task} = prx:fork(Ctrl),
 
  {'EXIT', {undef, _}} = (catch prx:getpid(Task)).

See also: filter/3.

Link to this function

filter(Task, Calls, SubprocessCalls)

View Source
-spec filter(task(),
       [call()] | {allow, [call()]} | {deny, [call()]},
       [call()] | {allow, [call()]} | {deny, [call()]}) ->
          ok.

filter/3 : restrict control process and subprocess calls

filter/3 specifies the set of calls available to a prx control process and any subsequently forked control processes. Control processes continue to proxy data and monitor and reap subprocesses.

Invoking a filtered call will crash the process with 'undef'.

If the filter/3 call is filtered, subsequent calls to filter/3 will fail.

Calls can be either allowed or denied. If a call is allowed, all other calls are filtered.

Once a filter for a call is added, the call cannot be removed from the filter set. Passing an empty list ([]) specifies the current filter set should not be modified.

  % the set of calls to filter, any forked control subprocesses
  % are unrestricted
  prx:filter(Task, {deny, [getpid, execve, execvp]}, [])
 
  % equivalent to {deny, [getpid, execve, execvp]}
  prx:filter(Task, [getpid, execve, execvp], [])
 
  % all other calls are filtered including filter
  prx:filter(Task, {allow, [fork, clone, kill]}, [])
 
  % init: control process can fork, subprocesses can exec a data process
  prx:filter(Task, {allow, [fork, clone, kill]}, {allow, [execve, execvp]})

examples

Examples

  1> catch_exception(true).
  false
  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  %% % Control process: restricted to: fork, filter, getcwd
  %% % Any forked control subprocess: restricted to: getpid, gethostname
  2> prx:filter(Task, {allow, [fork, filter, getcwd]}, {allow, [getpid, gethosname]}).
  ok
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.190.0>}
  4> prx:getpid(Task).
  * exception error: undefined function prx:getpid/1
  5> prx:getcwd(Task1).
  * exception error: undefined function prx:getcwd/1
  6> prx:getcwd(Task).
  {ok,<<"/">>}
-spec fork() -> {ok, task()} | {error, posix()}.

fork(2): create a new system process

The behaviour of the process can be controlled by setting the application environment:

  Option = {exec, string()}
   | {progname, string()}
   | {ctldir, string()}

{exec, Exec}

Default: ""

Sets a command to run the port under such as sudo or valgrind.

For example, to start the process as root using sudo, allow running prx as root:

   sudo visudo -f /etc/sudoers.d/99_prx
   <user> ALL = NOPASSWD: /path/to/prx/priv/prx
   Defaults!/path/to/prx/priv/prx !requiretty
   ```
 
   Then:
 
   ```
   application:set_env(prx, options, [{exec, "sudo -n"}])

{progname, Path}

Default: priv/prx

Sets the path to the prx executable.

{ctldir, Path}

Default: priv

A control directory writable by the prx port process (the Unix process may be running under a different user than the Erlang VM).

The control directory contains a FIFO shared by beam and the port process which is used to notify the Erlang VM that the port process has called exec().

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.187.0>}
-spec fork(task()) -> {ok, task()} | {error, posix()}.

fork(2): create a child process

Forks child processes from an existing task. For example:

  {ok, Task} = prx:fork(),             % PID 16341
  {ok, Child1} = prx:fork(Task),       % PID 16349
  {ok, Child2} = prx:fork(Task),       % PID 16352
  {ok, Child2a} = prx:fork(Child2),    % PID 16354
  {ok, Child2aa} = prx:fork(Child2a),  % PID 16357
  {ok, Child2ab} = prx:fork(Child2a).  % PID 16482

Results in a process tree:

  prx(16341)-+-prx(16349)
             `-prx(16352)---prx(16354)-+-prx(16357)
                                       `-prx(16482)

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.187.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.191.0>}
  3> prx:cpid(Task).
  [#{exec => false,fdctl => 8,flowcontrol => -1,pid => 8098,
     signaloneof => 15,stderr => 13,stdin => 10,stdout => 11}]
-spec getcpid(task(), atom()) -> int32_t() | false.

Get control process attributes

Retrieve attributes set by the prx control process %% for a child process.

See also: getcpid/3.

-spec getcpid(task(), task() | cpid() | pid_t(), atom()) -> int32_t() | false.

Get control process attributes

Retrieves attributes set by the prx 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

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.178.0>}
  3> prx:getcpid(Task, Task1, flowcontrol).
  -1
-spec getcwd(task()) -> {ok, binary()} | {error, posix()}.

getcwd(3): return the current working directory

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:chdir(Task, "/").
  ok
  3> prx:getcwd(Task).
  {ok,<<"/">>}
-spec getenv(task(), iodata()) -> binary() | false.

getenv(3): retrieve an environment variable

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:chdir(Task, "/").
  ok
  6> prx:getenv(Task, "TERM").
  <<"screen">>
-spec getgid(task()) -> gid_t().

getgid(2): retrieve the process group ID

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getgid(Task).
  1000
-spec getgroups(task()) -> {ok, [gid_t()]} | {error, posix()}.

getgroups(2): retrieve the list of supplementary groups

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getgroups(Task).
  {ok,[24,20,1000]}
-spec gethostname(task()) -> {ok, binary()} | {error, posix()}.

gethostname(2): retrieve the system hostname

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:gethostname(Task).
  {ok,<<"host1">>}
-spec getopt(task(), prx_opt()) -> false | int32_t().

Retrieve port options for event loop

Options are configurable per process, with the default settings inherited from the parent.

• 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 prx 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 prx control process is closed).

See setcpid/5.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getopt(Task, maxchild).
  64
-spec getpgrp(task()) -> pid_t().

getpgrp(2): retrieve the process group

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getpgrp(Task).
  3924
-spec getpid(task()) -> pid_t().

getpid(2): retrieve the system PID of the process

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getpid(Task).
  3924
Link to this function

getpriority(Task, Which, Who)

View Source
-spec getpriority(task(), constant(), int32_t()) -> {ok, int32_t()} | {error, posix()}.

getpriority(2): retrieve scheduling priority of process, process group or user

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getpriority(Task).
  {ok,0}
-spec getresgid(task()) -> {ok, gid_t(), gid_t(), gid_t()} | {error, posix()}.

getresgid(2): get real, effective and saved group ID

support

Support

• Linux

• OpenBSD

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getresgid(Task).
  {ok,1000,1000,1000}
-spec getresuid(task()) -> {ok, uid_t(), uid_t(), uid_t()} | {error, posix()}.

getresuid(2): get real, effective and saved user ID

support

Support

• Linux

• OpenBSD

• FreeBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getresuid(Task).
  {ok,1000,1000,1000}
Link to this function

getrlimit(Task, Resource)

View Source
-spec getrlimit(task(), constant()) -> {ok, #{cur => uint64_t(), max => uint64_t()}} | {error, posix()}.

getrlimit(2): retrieve the resource limits for a process

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> prx:getrlimit(Task, rlimit_nofile).
  {ok,#{cur => 1024,max => 1048576}}
-spec getsid(task(), pid_t()) -> {ok, pid_t()} | {error, posix()}.

getsid(2): retrieve the session ID

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getsid(Task).
  {ok,3924}
-spec getuid(task()) -> uid_t().

getuid(2): returns the process user ID

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  2> prx:getuid(Task).
  1000
Link to this function

ioctl(Task, FD, Request, Argp)

View Source
-spec ioctl(task(), fd(), constant(), cstruct()) ->
         {ok, #{return_value := integer(), arg := iodata()}} | {error, posix()}.

ioctl(2) : control device

Controls a device using a file descriptor previously obtained using open/4.

Argp can be either a binary or a list representation of a C struct. See prctl/6 below for a description of the list elements.

On success, ioctl/4 returns a 2-tuple containing a map. The map keys are:

• return_value: an integer equal to the return value of the ioctl.

Usually 0, however some ioctl's on Linux use the return value as the output parameter.

• arg: 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

Examples

An example of creating a tap device in a net namespace on Linux:

  {ok, Child} = prx:clone(Task, [clone_newnet]),
  {ok, FD} = prx:open(Child, "/dev/net/tun", [o_rdwr], 0),
  {ok, #{return_value = 0, arg = <<"tap", N, _/binary>>}} = prx:ioctl(Child, FD,
      tunsetiff, <<
      0:(16*8), % generate a tuntap device name
      (16#0002 bor 16#1000):2/native-unsigned-integer-unit:8, % IFF_TAP, IFF_NO_PI
      0:(14*8)
      >>),
  {ok, <<"tap", N>>}.
-spec jail(task(),
     #{version => alcove:uint32_t(),
       path => iodata(),
       hostname => iodata(),
       jailname => iodata(),
       ip4 => [inet:ip4_address()],
       ip6 => [inet:ip6_address()]} |
     cstruct()) ->
        {ok, int32_t()} | {error, posix()}.

jail(2): restrict the current process in a system jail

support

Support

• FreeBSD

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.155.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.159.0>}
  4> prx:jail(Task1, #{path => "/rescue", hostname => "test0", jailname => "test0"}).
  {ok,23223}
  5> prx:gethostname(Task1).
  {ok,<<"test0">>}
Link to this function

kill(Task, OSPid, Signal)

View Source
-spec kill(task(), pid_t(), constant()) -> ok | {error, posix()}.

kill(2): terminate a process

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.158.0>}
  3> Pid = prx:getpid(Task1).
  70524
  4> prx:kill(Task, 0, 0).
  ok
  5> prx:kill(Task, 12345, 0).
  {error,esrch}
  6> prx:kill(Task, Pid, 0).
  ok
  7> prx:kill(Task, Pid, sigkill).
  ok
  8> prx:kill(Task, Pid, 0).
  {error,esrch}
  9> flush().
  Shell got {termsig,<0.158.0>,sigkill}
  ok
Link to this function

lseek(Task, FD, Offset, Whence)

View Source
-spec lseek(task(), fd(), off_t(), int32_t()) -> ok | {error, posix()}.

lseek(2): set file offset for read/write

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.154.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.169.0>}
  3> {ok, FD} = prx:open(Task1, "/etc/passwd", [o_rdonly]).
  {ok,7}
  4> prx:lseek(Task1, FD, 0, 0).
  ok
-spec mkdir(task(), iodata(), mode_t()) -> ok | {error, posix()}.
mkdir(2) : create a directory
Link to this function

mkfifo(Task, Path, Mode)

View Source
-spec mkfifo(task(), iodata(), mode_t()) -> ok | {error, posix()}.
mkfifo(3) : create a named pipe
Link to this function

mount(Task, Source, Target, FSType, Flags, Data)

View Source
-spec mount(task(), iodata(), iodata(), iodata(), uint64_t() | [constant()], iodata()) ->
         ok | {error, posix()}.

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 mount namespace using the MS_REC|MS_PRIVATE flags:

  {ok, Task} = prx:clone(Parent, [clone_newns]),
  ok = prx:mount(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);

examples

Examples

An example of bind mounting a directory within a linux mount namespace:

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.192.0>}
  3> {ok, Task1} = prx:clone(Task, [clone_newns]).
  {ok,<0.196.0>}
  3> prx:mount(Task1, "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "").
  ok
  4> prx:umount(Task1, "/mnt").
  ok
Link to this function

mount(Task, Source, Target, FSType, Flags, Data, Options)

View Source
-spec mount(task(), iodata(), iodata(), iodata(), uint64_t() | [constant()], iodata(), iodata()) ->
         ok | {error, posix()}.

(Solaris) mount(2) : mount a filesystem

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.

See also: mount/6.

-spec open(task(), iodata(), int32_t() | [constant()]) -> {ok, fd()} | {error, posix()}.

open(2): returns a file descriptor associated with a file

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.192.0>}
  2> prx:open(Task, "/etc/hosts", [o_rdonly]).
  {ok,7}
Link to this function

open(Task, Path, Flags, Mode)

View Source
-spec open(task(), iodata(), int32_t() | [constant()], mode_t()) -> {ok, fd()} | {error, posix()}.

open(2) : open a file specifying permissions

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.192.0>}
  2> prx:open(Task, "/tmp/prx-open-test", [o_wronly,o_creat], 8#644).
  {ok,7}
-spec parent(task()) -> task() | noproc.

Get the parent PID for the task

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.208.0>}
  3> prx:parent(Task).
  noproc
  4> prx:parent(Task1).
  <0.180.0>
-spec pidof(task()) -> pid_t() | noproc.

Retrieves the system PID of the process similar to getpid(2)

Returns the cached value for the PID of the system process. Works with tasks in exec mode.

Warning: pidof/1 for a task returned by fork/0 returns the PID of the first child process. If using sudo/0, the PID for the sudo helper process is returned.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.182.0>}
  3> {ok, Task2} = prx:fork(Task).
  {ok,<0.184.0>}
  4> prx:execvp(Task1, ["cat"]).
  ok
  5> prx:getpid(Task2).
  27810
  7> prx:pidof(Task2).
  27810
  8> prx:pidof(Task1).
  27809
-spec pipeline(task()) -> [pid_t()].

Get the process pipeline list for the task

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> prx:getpid(Task).
  8094
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.208.0>}
  4> prx:getpid(Task1).
  8175
  5> {ok, Task2} = prx:fork(Task1).
  {ok,<0.3006.0>}
  6> prx:getpid(Task2).
  27224
  7> prx:pipeline(Task2).
  [8175,27224]
Link to this function

pivot_root(Task, NewRoot, PutOld)

View Source
-spec pivot_root(task(), iodata(), iodata()) -> ok | {error, posix()}.

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

Support

• Linux

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.192.0>}
  3> {ok, Task1} = prx:clone(Task, [clone_newns]).
  {ok,<0.196.0>}
  4> prx:mkdir(Task, "/tmp/prx-root", 8#755).
  ok
  5> {ok, Task1} = prx:clone(Task, [clone_newns]).
  {ok,<0.210.0>}
  6> prx:mount(Task1, "none", "/", [], [ms_rec, ms_private], []).
  ok
  7> prx:mount(Task1, "/tmp/prx-root", "/tmp/prx-root", [], [ms_bind], []).
  ok
  8> prx:chdir(Task1, "/tmp/prx-root").
  ok
  9> prx:pivot_root(Task1, ".", ".").
  ok
  10> prx:umount2(Task1, ".", [mnt_detach]).
  ok
Link to this function

pledge(Task, Promises, ExecPromises)

View Source
-spec pledge(task(), iodata(), iodata()) -> ok | {error, posix()}.

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

Support

• OpenBSD

examples

Examples

Fork a control process:

• restricted to stdio, proc and exec capabilities

• unrestricted after calling exec

  1> {ok, Task} = prx:fork().
  {ok,<0.152.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.156.0>}
  3> prx:pledge(Task, <<"stdio proc exec">>, []).
  ok
Link to this function

prctl(Task, Arg1, Arg2, Arg3, Arg4, Arg5)

View Source
-spec prctl(task(), constant(), ptr_arg(), ptr_arg(), ptr_arg(), ptr_arg()) ->
         {ok, integer(), ptr_val(), ptr_val(), ptr_val(), ptr_val()} | {error, posix()}.

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 zero'ed memory is allocated. 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

Support

• Linux

examples

Examples

The prx process requires the following syscalls to run:

    sys_exit
    sys_exit_group
    sys_getrlimit
    sys_poll
    sys_read
    sys_restart_syscall
    sys_rt_sigreturn
    sys_setrlimit
    sys_sigreturn
    sys_ugetrlimit
    sys_write
    sys_writev

To enforce a seccomp filter:

  -module(seccomp).
 
  -include_lib("alcove/include/alcove_seccomp.hrl").
 
  -export([run/1, run/2, filter/2]).
 
  -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(Task, Syscall) ->
      Arch = prx:call(Task, syscall_constant, [alcove:audit_arch()]),
      NR = prx:call(Task, syscall_constant, [Syscall]),
 
      [
          ?VALIDATE_ARCHITECTURE(Arch),
          ?EXAMINE_SYSCALL,
          ?DENY_SYSCALL(NR),
          ?BPF_STMT(?BPF_RET + ?BPF_K, ?SECCOMP_RET_ALLOW)
      ].
 
  run(Task) ->
      run(Task, sys_getcwd).
 
  run(Task, Syscall) ->
      Filter = filter(Task, Syscall),
 
      {ok, _, _, _, _, _} = prx:prctl(Task, 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)}
      ],
      %% prx:seccomp(Task, seccomp_set_mode_filter, 0, Prog)
      prx:prctl(Task, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).

To enforce the filter:

  1> catch_exception(true).
  false
  2> {ok, Task} = prx:fork().
  {ok,<0.186.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.191.0>}
  4> seccomp:run(Task1, sys_getcwd).
  {ok,0,2,
      [<<7,0>>,
       <<0,0,0,0,0,0>>,
       {ptr,<<32,0,0,0,4,0,0,0,21,0,1,0,62,0,0,192,6,0,0,0,...>>}],
      0,0}
  5> prx:getcwd(Task1).

See also: seccomp/4.

Link to this function

procctl(Task, IDType, ID, Cmd, Data)

View Source
-spec procctl(task(), constant(), pid_t(), constant(), [] | cstruct()) ->
           {ok, binary(), cstruct()} | {error, posix()}.

procctl(2): control processes

support

Support

• FreeBSD

examples

Examples

  Pid = prx:pidof(Task),
  prx:procctl(Task, 0, Pid, 'PROC_REAP_ACQUIRE', []),
  prx:procctl(Task, p_pid, Pid, 'PROC_REAP_STATUS', [
     <<0,0,0,0>>, % rs_flags
     <<0,0,0,0>>, % rs_children
     <<0,0,0,0>>, % rs_descendants
     <<0,0,0,0>>, % rs_reaper
     <<0,0,0,0>>  % rs_pid
  ]).
Link to this function

ptrace(Task, Request, OSPid, Addr, Data)

View Source
-spec ptrace(task(), constant(), pid_t(), ptr_arg(), ptr_arg()) ->
          {ok, integer(), ptr_val(), ptr_val()} | {error, posix()}.

ptrace(2): process trace

examples

Examples

  -module(ptrace).
 
  -export([run/0]).
 
  run() ->
      {ok, Task} = prx:fork(),
      {ok, Task1} = prx:fork(Task),
      {ok, Task2} = prx:fork(Task1),
 
      Pid2 = prx:pidof(Task2),
 
      % disable the prx event loop: child process must be managed by
      % the caller
      {ok, sig_dfl} = prx:sigaction(Task1, sigchld, sig_info),
 
      % enable ptracing in the child process and exec() a command
      {ok, 0, <<>>, <<>>} = prx:ptrace(Task2, ptrace_traceme, 0, 0, 0),
      ok = prx:execvp(Task2, "cat", ["cat"]),
 
      % the parent is notified
      ok =
          receive
              {signal, Task1, sigchld, _} ->
                  ok
          after 5000 ->
              timeout
          end,
 
      {ok, Pid2, _, [{stopsig, sigtrap}]} = prx:waitpid(Task1, -1, [wnohang]),
 
      % should be no other events
      {ok, 0, 0, []} = prx:waitpid(Task1, -1, [wnohang]),
 
      % allow the process to continue
      {ok, 0, <<>>, <<>>} = prx:ptrace(Task1, ptrace_cont, Pid2, 0, 0),
 
      ok = prx:stdin(Task2, "test\n"),
 
      ok =
          receive
              {stdout, Task2, <<"test\n">>} ->
                  ok
          after 5000 -> timeout
          end,
 
      % Send a SIGTERM and re-write it to a harmless SIGWINCH
      ok = prx:kill(Task1, Pid2, sigterm),
      ok =
          receive
              {signal, Task1, sigchld, _} ->
                  ok
          after 5000 ->
              timeout
          end,
 
      {ok, Pid2, _, [{stopsig, sigterm}]} = prx:waitpid(Task1, -1, [wnohang]),
 
      {ok, 0, <<>>, <<>>} = prx:ptrace(Task1, ptrace_cont, Pid2, 0, 28),
 
      % Convert a SIGWINCH to SIGTERM
      ok = prx:kill(Task1, Pid2, sigwinch),
      ok =
          receive
              {signal, Task1, sigchld, _} ->
                  ok
          after 5000 ->
              timeout
          end,
 
      {ok, 0, <<>>, <<>>} = prx:ptrace(Task1, ptrace_cont, Pid2, 0, 15),
      {ok, Pid2, _, [{termsig, sigterm}]} = prx:waitpid(Task1, -1, []).
-spec read(task(), fd(), size_t()) -> {ok, binary()} | {error, posix()}.

read(2): read bytes from a file descriptor

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.212.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.216.0>}
  3> {ok, FD} = prx:open(Task1, "/etc/hosts", [o_rdonly]).
  {ok,7}
  4> prx:read(Task1, FD, 64).
  {ok,<<"127.0.0.1 localhost\n\n# The following lines are desirable for IPv">>}
-spec readdir(task(), iodata()) -> {ok, [binary()]} | {error, posix()}.

readdir(3): retrieve list of objects in a directory

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.212.0>}
  2> prx:readdir(Task, "/dev/pts").
  {ok,[<<".">>,<<"..">>,<<"66">>,<<"63">>,<<"67">>,<<"64">>,
       <<"62">>,<<"61">>,<<"60">>,<<"59">>,<<"58">>,<<"57">>,
       <<"56">>,<<"55">>,<<"54">>,<<"53">>,<<"52">>,<<"51">>,
       <<"50">>,<<"49">>,<<"48">>,<<"47">>,<<"46">>,<<"45">>,
       <<"44">>,<<"43">>,<<...>>|...]}
-spec reexec(task()) -> ok | {error, posix()}.

Fork+exec prx process.

Fork+exec is a way of randomizing the memory space of a process:

https://poolp.org/posts/2016-09-12/opensmtpd-6.0.0-is-released/

prx processes fork recursively:

• the calls stack increases in size

• the memory space layout is identical to the parent

After forking a prx process using fork/1, the controlling process will typically instruct the new prx process to execute a command using one of the exec(3) functions: execvp/2, execve/3.

Some "system" or "supervisor" type processes may remain in call mode: these processes can call reexec/1 to exec() the port.

On platforms supporting fexecve(2) (FreeBSD, Linux), prx will open a file descriptor to the port binary and use it to re-exec() the port.

On other OS'es, execve(2) will be used with the the default path to the port binary.

If the binary is not accessible or, on Linux, /proc is not mounted, reexec/1 will fail.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.216.0>}
  2> prx:getpid(Task1).
  8175
  3> prx:reexec(Task1).
  ok
  4> prx:getpid(Task1).
  8175
-spec reexec(task(), {fd, int32_t(), [string() | [string()]]} | [string() | [string()]], iodata()) ->
          ok | {error, posix()}.

Replace the port process image using execve(2)/fexecve(2).

Specify the port program path or a file descriptor to the binary and the process environment.

See also: reexec/1.

Link to this function

replace_process_image(Task)

View Source
-spec replace_process_image(task()) -> ok | {error, posix()}.

Equivalent to reexec / 1.

Link to this function

replace_process_image(Task, Argv, Env)

View Source
-spec replace_process_image(task(),
                      {fd, int32_t(), [string() | [string()]]} | [string() | [string()]],
                      iodata()) ->
                         ok | {error, posix()}.

Equivalent to reexec / 3.

-spec rmdir(task(), iodata()) -> ok | {error, posix()}.

rmdir(2): delete a directory

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.212.0>}
  2> prx:mkdir(Task, "/tmp/prx-rmdir-test", 8#755).
  ok
  3> prx:rmdir(Task, "/tmp/prx-rmdir-test").
  ok
Link to this function

seccomp(Task, Operation, Flags, Prog)

View Source
-spec seccomp(task(), constant(), constant(), cstruct()) -> ok | {error, posix()}.

seccomp(2) : restrict system operations

support

Support

• Linux

examples

Examples

  %% Equivalent to:
  %% prx:prctl(Task, pr_set_seccomp, seccomp_mode_filter, Prog, 0, 0).
  prx:seccomp(Task, seccomp_set_mode_filter, 0, Prog)

See also: prctl/6.

Link to this function

select(Task, Readfds, Writefds, Exceptfds, Timeval)

View Source
-spec select(task(),
       Readfds :: [fd()],
       Writefds :: [fd()],
       Exceptfds :: [fd()],
       Timeval :: [] | #{sec => int64_t(), usec => int64_t()}) ->
          {ok, [fd()], [fd()], [fd()]} | {error, posix()}.

select(2): poll a list of file descriptor for events

select/5 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)

• a map indicating the timeout

The map contains these fields:

• sec : number of seconds to wait

• usec : number of microseconds to wait

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, FD} = prx:open(Task, "/dev/null", [o_rdwr], 0).
  {ok,7}
  3> prx:select(Task, [FD], [FD], [FD], []).
  {ok,[7],[7],[]}
  4> prx:select(Task, [FD], [FD], [FD], #{sec => 1, usec => 1}).
  {ok,[7],[7],[]}
-spec setcpid(task(), atom(), int32_t()) -> boolean().

setcpid() : Set options for child process of prx control process

Control behaviour of an exec()'ed process.

See also: setcpid/4.

Link to this function

setcpid(Task, Pid, Opt, Val)

View Source
-spec setcpid(task(), task() | cpid() | pid_t(), atom(), int32_t()) -> boolean().

setcpid() : Set options for child process of prx 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

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:setcpid(Task1, flowcontrol, 0).
  true
  4> prx:getcpid(Task1, flowcontrol).
  0
Link to this function

setenv(Task, Name, Value, Overwrite)

View Source
-spec setenv(task(), iodata(), iodata(), int32_t()) -> ok | {error, posix()}.

setenv(3): set an environment variable

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> prx:setenv(Task, "TEST", "foo", 0).
  ok
  3> prx:getenv(Task, "TEST").
  <<"foo">>
  4> prx:setenv(Task, "TEST", "bar", 0).
  ok
  5> prx:getenv(Task, "TEST").
  <<"foo">>
  6> prx:setenv(Task, "TEST", "bar", 1).
  ok
  7> prx:getenv(Task, "TEST").
  <<"bar">>
-spec setgid(task(), gid_t()) -> ok | {error, posix()}.

setgid(2): set the GID of the process

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.159.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.163.0>}
  4> prx:setgid(Task1, 123).
  ok
  5> prx:getgid(Task1).
  123
-spec setgroups(task(), [gid_t()]) -> ok | {error, posix()}.

setgroups(2): set the supplementary groups of the process

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.160.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.164.0>}
  4> prx:setgroups(Task1, []).
  ok
  5> prx:getgroups(Task1).
  {ok,[]}
Link to this function

sethostname(Task, Hostname)

View Source
-spec sethostname(task(), iodata()) -> ok | {error, posix()}.

sethostname(2): set the system hostname

This function is probably only useful if running in a uts namespace or a jail.

examples

Examples

  {ok, Child} = prx:clone(Task, [clone_newuts]),
  ok = prx:sethostname(Child, "test"),
  Hostname1 = prx:gethostname(Task),
  Hostname2 = prx:gethostname(Child),
  Hostname1 =/= Hostname2.
-spec setns(task(), fd()) -> ok | {error, posix()}.

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

Support

• Linux

examples

Examples

Attach a process to an existing network namespace:

  {ok, Child1} = prx:clone(Task, [clone_newnet]),
  {ok, Child2} = prx:fork(Task),
 
  % Move Child2 into the Child1 network namespace
  {ok, FD} = prx:open(
      Child2,
      ["/proc/", integer_to_list(Child1), "/ns/net"],
      [o_rdonly],
      0
  ),
  ok = prx:setns(Child2, FD),
  ok = prx:close(Child2, FD).
-spec setns(task(), fd(), constant()) -> ok | {error, posix()}.

(Linux) setns(2) : attach to a namespace, specifying namespace type

  ok = prx:setns(Task, FD, clone_newnet)

See also: setns/2.

-spec setopt(task(), prx_opt(), int32_t()) -> boolean().

Set port options

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.160.0>}
  2> prx:setopt(Task, maxforkdepth, 128).
  true

See also: getopt/2.

Link to this function

setpgid(Task, OSPid, Pgid)

View Source
-spec setpgid(task(), pid_t(), pid_t()) -> ok | {error, posix()}.

setpgid(2): set process group

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:setpgid(Task1, 0, 0).
  ok
Link to this function

setpriority(Task, Which, Who, Prio)

View Source
-spec setpriority(task(), constant(), int32_t(), int32_t()) -> ok | {error, posix()}.

setpriority(2): set scheduling priority of process, process group or user

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:setpriority(Task1, prio_process, 0, 10).
  ok
  4> prx:getpriority(Task1, prio_process, 0).
  {ok,10}
Link to this function

setproctitle(Task, Name)

View Source
-spec setproctitle(task(), iodata()) -> ok.

setproctitle(3): set the process title

Set the process title displayed in utilities like ps(1) by overwriting the command's arg0.

Linux systems may also want to set the command name using prctl/6:

  prx:prctl(Task, pr_set_name, <<"newname">>, 0, 0, 0)

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.177.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,28210}
  3> prx:setproctitle(Task1, "new process name").
  ok

See also: prctl/6.

Link to this function

setresgid(Task, Real, Effective, Saved)

View Source
-spec setresgid(task(), gid_t(), gid_t(), gid_t()) -> ok | {error, posix()}.

setresgid(2): set real, effective and saved group ID

support

Support

• Linux

• FreeBSD

• OpenBSD

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  4> prx:setresgid(Task1, 123, 123, 123).
  ok
Link to this function

setresuid(Task, Real, Effective, Saved)

View Source
-spec setresuid(task(), uid_t(), uid_t(), uid_t()) -> ok | {error, posix()}.

setresuid(2): set real, effective and saved user ID

support

Support

• Linux

• FreeBSD

• OpenBSD

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:setresuid(Task1, 123, 123, 123).
  ok
Link to this function

setrlimit(Task, Resource, Limit)

View Source
-spec setrlimit(task(), constant(), #{cur => uint64_t(), max => uint64_t()}) -> ok | {error, posix()}.

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

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:getrlimit(Task1, rlimit_nofile).
  {ok,#{cur => 1048576,max => 1048576}}
  4> prx:setrlimit(Task1, rlimit_nofile, #{cur => 64, max => 64}).
  ok
  5> prx:getrlimit(Task1, rlimit_nofile).
  {ok,#{cur => 64,max => 64}}
  6> prx:getrlimit(Task, rlimit_nofile).
  {ok,#{cur => 1048576,max => 1048576}}
-spec setsid(task()) -> {ok, pid_t()} | {error, posix()}.

setsid(2): create a new session

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:setsid(Task1).
  {ok,32141}
-spec setuid(task(), uid_t()) -> ok | {error, posix()}.

setuid(2): change UID

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:setuid(Task1, 123).
  ok
  3> prx:getuid(Task1).
  123

See also: setresuid/4.

-spec sh(task(), iodata()) -> binary() | {error, posix()}.
Link to this function

sigaction(Task, Signal, Handler)

View Source
-spec sigaction(task(),
          constant(),
          atom() | {sig_info, fun((pid(), [pid_t()], atom(), binary()) -> any())}) ->
             {ok, atom()} | {error, posix()}.

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

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.182.0>}
  3> prx:kill(Task, prx:pidof(Task1), sigterm).
  ok
  4> flush().
  Shell got {signal,<0.182.0>,sigterm,
                    <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,126,0,0,232,3,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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
  5> prx:sigaction(Task1, sigterm, sig_ign).
  {ok,sig_info}
  6> prx:kill(Task, prx:pidof(Task1), sigterm).
  ok
  7> flush().
  ok
  8> prx:sigaction(Task1, sigterm, sig_info).
  {ok,sig_ign}
  9> prx:kill(Task, prx:pidof(Task1), sigterm).
  ok
  10> flush().
  Shell got {signal,<0.182.0>,sigterm,
                    <<15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,126,0,0,232,3,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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
Link to this function

socket(Task, Domain, Type, Protocol)

View Source
-spec socket(task(), constant(), constant(), int32_t()) -> {ok, fd()} | {error, posix()}.

socket(2): returns a file descriptor for a communication endpoint

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, FD} = prx:socket(Task, af_inet, sock_stream, 0).
  {ok,7}
-spec stdin(task(), iodata()) -> ok.

Send data to the standard input of the process

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.194.0>}
  3> prx:execvp(Task1, ["cat", "-n"]).
  ok
  4> prx:stdin(Task1, <<"test\n">>).
  ok
  5> flush().
  Shell got {stdout,<0.194.0>,<<"     1\ttest\n">>}
  ok
-spec stdio(task(), pid()) -> ok | {error, badarg}.

Assign a process to receive stdio

Change the process receiving prx standard output and standard error.

stdio/2 and controlling_process/2 can be used to transfer a prx process between erlang processes without losing output when exec(3) is called:

  ok = prx:stdio(Owner, NewOwner),
  ok = prx:execvp(Owner, Argv),
  ok = prx:controlling_process(Owner, NewOwner).
-spec stop(task()) -> ok.

Terminate the task

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.180.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.184.0>}
  4> prx:stop(Task1).
  ok
  5> prx:cpid(Task).
  []
-spec sudo() -> ok.

Convenience function to fork a privileged process in the shell.

Sets the application environment so prx can fork a privileged process. sudo must be configured to run the prx binary.

The application environment must be set before prx:fork/0 is called.

Equivalent to:

  application:set_env(prx, options, [{exec, "sudo -n"}]),
  {ok, Task} = prx:fork(),
  0 = prx:getuid(Task).

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.199.0>}
  3> prx:getuid(Task).
  0
-spec sudo(iodata()) -> ok.

Convenience function to fork a privileged process in the shell.

Allows specifying the command.

examples

Examples

For example, on OpenBSD:

  1> prx:sudo("doas").
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.199.0>}
  3> prx:getuid(Task).
  0
-spec task(task(), Ops :: [prx_task:op() | [prx_task:op()]], State :: any()) ->
        {ok, task()} | {error, posix()}.

Fork a subprocess and run a sequence of operations

task/3 uses fork/1 to create a new subprocess and run a sequence of system calls. If an operations fails, the subprocess is sent SIGKILL and exits.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.349.0>}
  2> {ok, Task1} = prx:task(Task, [
  2>     {chdir, ["/"]},
  2>     {setrlimit, [rlimit_core, #{cur => 0, max => 0}]},
  2>     {prx, chdir, ["/nonexistent"], [{errexit, false}]}
  2> ], []).
  {ok,<0.382.0>}
  3> prx:getrlimit(Task1, rlimit_core).
  {ok,#{cur => 0,max => 0}}
  4> prx:getcwd(Task1).
  {ok,<<"/">>}

See also: task/4.

Link to this function

task(Task, Ops, State, Config)

View Source
-spec task(task(),
     Ops :: [prx_task:op() | [prx_task:op()]],
     State :: any(),
     Config :: [prx_task:config()]) ->
        {ok, task()} | {error, posix()}.

Create a subprocess and run a sequence of operations using optional function calls

task/4 calls the optional init function provided in the Config argument to create a new subprocess. The default init function uses fork/1.

The subprocess next performs a list of operations. Operations are tuples consisting of:

* the module name: optional if modifier is not present, defaults to prx

* the module function

* function arguments

* modifier list

  [
   % equivalent to prx:setresgid(65534, 65534, 65534)
   {setresgid, [65534, 65534, 65534]},
 
   % equivalent to prx:setresuid(65534, 65534, 65534), error is ignored
   {prx, setresuid, [65534, 65534, 65534], [{errexit, false}]},
  ]

If an operation returns {error, term()}, the sequence of operations is aborted and the terminate function is run. The default terminate functions signals the subprocess with SIGKILL.

examples

Examples

  1> Init = fun(Parent) ->
  1>     prx:clone(Parent, [
  1>         clone_newnet,
  1>         clone_newuser
  1>     ])
  1> end.
  #Fun<erl_eval.44.65746770>
  2> Terminate = fun(Parent, Child) ->
  2>     prx:stop(Child),
  2>     prx:kill(Parent, prx:pidof(Child), sigterm)
  2> end.
  #Fun<erl_eval.43.65746770>
  3> {ok, Task} = prx:fork().
  4> {ok, Task1} = prx:task(Task, [
  4>     {chdir, ["/"]},
  4>     {setrlimit, [rlimit_core, #{cur => 0, max => 0}]},
  4>     {prx, chdir, ["/nonexistent"], [{errexit, false}]}
  4> ], [], [
  4>     {init, Init},
  4>     {terminate, Terminate}
  4> ]).
  {ok,<0.398.0>}
  5> prx:execvp(Task1, ["ip", "a"]).
  ok
  27> flush().
  Shell got {stdout,<0.398.0>,
                    <<"1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000\n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n">>}
  Shell got {exit_status,<0.398.0>,0}
  ok

See also: prx_task.

Link to this function

umount2(Task, Path, Flags)

View Source
-spec umount2(task(), iodata(), [constant()]) -> ok | {error, posix()}.

umount2(2) : unmount a filesystem

On BSD systems, calls unmount(2).

examples

Examples

See also: pivot_root/3.

-spec umount(task(), iodata()) -> ok | {error, posix()}.

umount(2): unmount a filesystem

On BSD systems, calls unmount(2).

examples

Examples

An example of bind mounting a directory within a linux mount namespace:

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.192.0>}
  3> {ok, Task1} = prx:clone(Task, [clone_newns]).
  {ok,<0.196.0>}
  3> prx:mount(Task1, "/tmp", "/mnt", "", [ms_bind, ms_rdonly, ms_noexec], "").
  ok
  4> prx:umount(Task1, "/mnt").
  ok
-spec unlink(task(), iodata()) -> ok | {error, posix()}.

unlink(2): delete a name from the filesystem

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> prx:open(Task, "/tmp/testfile", [o_wronly, o_creat], 8#644).
  {ok,8}
  3> prx:unlink(Task, "/tmp/testfile").
  ok
-spec unsetenv(task(), iodata()) -> ok | {error, posix()}.

unsetenv(3): remove an environment variable

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> prx:setenv(Task, "TEST", "foo", 0).
  ok
  3> prx:getenv(Task, "TEST").
  <<"foo">>
  4> prx:unsetenv(Task, "TEST").
  ok
  5> prx:getenv(Task, "TEST").
  false
-spec unshare(task(), int32_t() | [constant()]) -> ok | {error, posix()}.

unshare(2): create a new namespace in the current process

Make a new namespace without calling clone(2):

  % The port is now running in a namespace without network access.
  ok = prx:unshare(Task, [clone_newnet]).

examples

Examples

  1> prx:sudo().
  ok
  2> {ok, Task} = prx:fork().
  {ok,<0.179.0>}
  3> {ok, Task1} = prx:fork(Task).
  {ok,<0.183.0>}
  4> prx:unshare(Task1, [clone_newuts]).
  ok
  5> prx:sethostname(Task1, "unshare").
  ok
  6> prx:gethostname(Task1).
  {ok,<<"unshare">>}
  7> prx:gethostname(Task).
  {ok,<<"host1">>}
Link to this function

unveil(Task, Path, Permissions)

View Source
-spec unveil(task(), iodata(), iodata()) -> ok | {error, posix()}.

unveil(2): restrict filesystem view

To disable unveil calls, use an empty list ([]) or, equivalently, an empty string ("").

  prx:unveil(Task, <<"/etc">>, <<"r">>),
  prx:unveil(Task, [], []).

support

Support

• OpenBSD

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.152.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.156.0>}
  3> prx:unveil(Task1, <<"/etc">>, <<"r">>).
  ok
  4> prx:unveil(Task1, [], []).
  ok
  5> prx:readdir(Task1, "/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> prx:readdir(Task1, "/tmp").
  {error,enoent}
Link to this function

waitpid(Task, OSPid, Options)

View Source
-spec waitpid(task(), pid_t(), int32_t() | [constant()]) ->
           {ok, pid_t(), int32_t(), [waitstatus()]} | {error, posix()}.

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:

  {ok, sig_dfl} = prx:sigaction(Task, sigchld, sig_info),
  {ok, Child} = prx:fork(Task),
  Pid = prx:getpid(Child),
  ok = prx:exit(Child, 2),
  {ok, Pid, _, [{exit_status, 2}]} = prx:waitpid(Task, Pid, [wnohang]).

Note: if the default SIGCHLD handler is disabled, waitpid/4,5 should be called to reap zombie processes:

  prx:waitpid(Task, -1, [wnohang])

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.158.0>}
  2> {ok, Task1} = prx:fork(Task).
  {ok,<0.162.0>}
  3> prx:sigaction(Task1, sigchld, sig_info).
  {ok,sig_dfl}
  4> prx:execvp(Task1, ["sleep", "20"]).
  ok
  5> prx:waitpid(Task, -1, []).
  {ok,30958,0,[{exit_status,0}]}

write(2): write to a file descriptor

Writes a buffer to a file descriptor and returns the number of bytes written.

examples

Examples

  1> {ok, Task} = prx:fork().
  {ok,<0.178.0>}
  2> {ok, FD} = prx:open(Task, "/tmp/testfile", [o_wronly, o_creat], 8#644).
  {ok,7}
  3> prx:write(Task, FD, <<"test">>).
  {ok,4}
-spec write(task(), fd(), iodata()) -> {ok, ssize_t()} | {error, posix()}.