### Manage Externally Started OS Process Source: https://hexdocs.pm/erlexec Explains how to manage an OS process that was started externally. This involves getting the OS PID, using `exec:manage/2` to monitor it, and receiving monitor notifications. ```erlang % Start an externally managed OS process and retrieve its OS PID: 17> spawn(fun() -> os:cmd("echo $$ > /tmp/pid; sleep 15") end). <0.330.0> 18> f(P), P = list_to_integer(lists:reverse(tl(lists:reverse(binary_to_list(element( 2, file:read_file("/tmp/pid")))))))). 19355 % Manage the process and get notified by a monitor when it exits: 19> exec:manage(P, [monitor]). {ok,<0.334.0>,19355} % Wait for monitor notification 20> f(M), receive M -> M end. {'DOWN',19355,process,<0.334.0>,{exit_status,10}} ok 21> file:delete("/tmp/pid"). ok ``` -------------------------------- ### Start and Run OS Process with Elixir Exec Source: https://hexdocs.pm/erlexec Shows how to start the exec port program and run shell commands using Elixir's exec module. Supports synchronous execution and capturing stdout. ```elixir iex(1)> :exec.start {:ok, #PID<0.112.0>} iex(2)> :exec.run("echo ok", [:sync, :stdout]) {:ok, [stdout: ["ok\n"]]} iex(3)> :exec.run(["/bin/echo", "ok"], [:sync, :stdout]) {:ok, [stdout: ["ok\n"]]} ``` -------------------------------- ### Set Up Monitor for OS Process Source: https://hexdocs.pm/erlexec Shows how to set up a monitor for an OS process started with `exec:run/2`. The `monitor` option will send a `{'DOWN',...}` message to the Erlang process when the OS process exits. ```erlang > f(I), f(P), {ok, P, I} = exec:run("echo ok", [{stdout, self()}, monitor]). {ok,<0.263.0>,18950} 16> flush(). Shell got {stdout,18950,<<"ok\n">>} Shell got {'DOWN',18950,process,<0.263.0>,normal} ok ``` -------------------------------- ### Run OS Process as Root Source: https://hexdocs.pm/erlexec Demonstrates running an OS process as root using `exec:start` with root privileges. Ensure `exec-port` has SUID bit set or use `sudo`. ```erlang $ sudo _build/default/lib/erlexec/priv/*/exec-port --whoami root $ erl 1> exec:start([root, {user, "root"}, {limit_users, ["root"]}]) 2> exec:run("whoami", [sync, stdout]). {ok, [{stdout, [<<"root\n">>]}]} ``` -------------------------------- ### Start and Stop OS Process with Erlexec Source: https://hexdocs.pm/erlexec Demonstrates starting the exec port program, running a shell command, and stopping the process. The process ID can be used to stop the command. ```erlang 1> exec:start(). % Start the port program. {ok,<0.32.0>} 2> {ok, _, I} = exec:run_link("sleep 1000", []). % Run a shell command to sleep for 1000s. {ok,<0.34.0>,23584} 3> exec:stop(I). % Kill the shell command. ok % Note that this could also be accomplished % by doing exec:stop(pid(0,34,0)). ``` -------------------------------- ### Run exec-port as Another User with Erlexec Source: https://hexdocs.pm/erlexec Demonstrates starting the exec port program as a different effective user using the `{user, User}` option. Requires appropriate permissions or SUID setup for the exec-port binary. ```shell $ ll priv/x86_64-unknown-linux-gnu/exec-port -rwsr-xr-x 1 root root 777336 Dec 8 10:02 ./priv/x86_64-unknown-linux-gnu/exec-port ``` ```erlang 1> exec:start([{user, "wheel"}, {portexe, "/tmp/exec-port"}]). % Start the port program as effective user "wheel". {ok,<0.32.0>} ``` ```shell $ cp $(find . -name exec-port) /tmp $ chmod 755 /tmp/exec-port $ whoami serge $ erl 1> exec:start([{user, "wheel"}, {portexe, "/tmp/exec-port"}]). % Start the port program as effective user "wheel". {ok,<0.32.0>} $ ps haxo user,comm | grep exec-port wheel exec-port ``` -------------------------------- ### Allow exec-port to Run Commands as Limited Users Source: https://hexdocs.pm/erlexec Shows how to configure exec-port to run commands as specific users from a limited list, after starting as root and switching to an initial user. Requires SUID and capabilities. ```erlang 1> Opts = [root, {user, "wheel"}, {limit_users, ["alex","guest"]}], 2> exec:start(Opts). % Start the port program as effective user "wheel" % and allow it to execute commands as "alex" or "guest". {ok,<0.32.0>} 3> exec:run("whoami", [sync, stdout, {user, "alex"}]). % Command is executed under effective user "alex" {ok,[{stdout,[<<"alex\n">>]}]} ``` ```shell $ whoami serge $ erl 1> Opts = [root, {user, "wheel"}, {limit_users, ["alex","guest"]}], 2> exec:start(Opts). % Start the port program as effective user "wheel" % and allow it to execute commands as "alex" or "guest". {ok,<0.32.0>} 3> exec:run("whoami", [sync, stdout, {user, "alex"}]). % Command is executed under effective user "alex" {ok,[{stdout,[<<"alex\n">>]}]} $ ps haxo user,comm | grep exec-port wheel exec-port ``` -------------------------------- ### Run OS Commands Synchronously Source: https://hexdocs.pm/erlexec Execute OS commands synchronously, capturing their termination code and optionally their stdout and stderr. Examples demonstrate capturing output, handling non-existent commands, and redirecting stderr to stdout. ```erlang % Execute an shell script that blocks for 1 second and return its termination code 29> exec:run("sleep 1; echo Test", [sync]). % By default all I/O is redirected to /dev/null, so no output is captured {ok,[]} % 'stdout' option instructs the port program to capture stdout and return it to caller 30> exec:run("sleep 1; echo Test", [stdout, sync]). {ok,[{stdout, [<<"Test\n">>]}]} % Execute a non-existing command 31> exec:run("echo1 Test", [sync, stdout, stderr]). {error,[{exit_status,32512}, {stderr,[<<"/bin/bash: echo1: command not found\n">>]}]} % Capture stdout/stderr of the executed command 32> exec:run("echo Test; echo Err 1>&2", [sync, stdout, stderr]). {ok,[{stdout,[<<"Test\n">>]},{stderr,[<<"Err\n">>]}]} % Redirect stderr to stdout 33> exec:run("echo Test 1>&2", [{stderr, stdout}, stdout, sync]). {ok, [{stdout, [<<"Test\n">>]}]} ``` -------------------------------- ### Run OS Commands with/without Shell Source: https://hexdocs.pm/erlexec Execute OS commands either through a shell interpreter or directly as an executable. When not using a shell, the full path to the executable is required. Examples show executing commands with and without a shell, and with custom shell options. ```erlang % Execute a command by an OS shell interpreter 34> exec:run("echo ok", [sync, stdout]). {ok, [{stdout, [<<"ok\n">>]}]} % Execute an executable without a shell (note that in this case % the full path to the executable is required): 35> exec:run(["/bin/echo", "ok"], [sync, stdout]). {ok, [{stdout, [<<"ok\n">>]}]} % Execute a shell with custom options 36> exec:run(["/bin/bash", "-c", "echo ok"], [sync, stdout]). {ok, [{stdout, [<<"ok\n">>]}]} ``` -------------------------------- ### Communicate with OS Process via STDIN Source: https://hexdocs.pm/erlexec Execute an OS process that reads STDIN and echoes it back. Data is sent to the process's stdin, and the response is captured from its stdout. The example also confirms the process's exit. ```erlang % Execute an OS process (script) that reads STDIN and echoes it back to Erlang 25> f(I), {ok, _, I} = exec:run("read x; echo \"Got: $x\"", [stdin, stdout, monitor]). {ok,<0.427.0>,26431} % Send the OS process some data via its stdin 26> exec:send(I, <<"Test data\n">>). ok % Get the response written to processes stdout 27> f(M), receive M -> M after 10000 -> timeout end. {stdout,26431,<<"Got: Test data\n">>} % Confirm that the process exited 28> f(M), receive M -> M after 10000 -> timeout end. {'DOWN',26431,process,<0.427.0>,normal} ``` -------------------------------- ### Build Erlexec from source Source: https://hexdocs.pm/erlexec Commands to clone and build the project from the repository. ```bash $ git clone git@github.com:saleyn/erlexec.git $ make # NOTE: for disabling optimized build of exec-port, do the following instead: $ OPTIMIZE=0 make ``` -------------------------------- ### Append OS Process stdout to File Source: https://hexdocs.pm/erlexec Demonstrates appending the standard output of an OS process to a file using the `stdout` option with a file path and the `append` option. The file mode can also be specified. ```erlang 13> exec:run("for i in 1 2 3; do echo TEST$i; done", [{stdout, "/tmp/out", [append, {mode, 8#600}]}, sync]), file:read_file("/tmp/out"). {ok,<<"TEST1\nTEST2\nTEST3\n">>} 14> exec:run("echo Test4; done", [{stdout, "/tmp/out", [append, {mode, 8#600}]}, sync]), file:read_file("/tmp/out"). {ok,<<"TEST1\nTEST2\nTEST3\nTest4\n">>} 15> file:delete("/tmp/out"). ``` -------------------------------- ### Manage Environment Variables with Erlexec Source: https://hexdocs.pm/erlexec Illustrates clearing the environment, adding new variables, and unsetting existing variables for child processes using the `{env, ...}` option. ```erlang %% Clear environment with {env, [clear]} option: 10> f(Bin), {ok, [{stdout, [Bin]}]} = exec:run("env", [sync, stdout, {env, [clear]}]), io:format("~s\n", [re:split(Bin, <<"\n">>)]). [<<"PWD=/home/...">>,<<"SHLVL=0">>, <<"_=/usr/bin/env">>,<<>>] ok %% Clear env and add a "TEST" env variable: 11> f(Bin), {ok, [{stdout, [Bin]}]} = exec:run("env", [sync, stdout, {env, [clear, {"TEST", "xxx"}]}]), io:format("~s\n", [re:split(Bin, <<"\n">>)]). [<<"PWD=/home/...">>,<<"SHLVL=0">>, <<"_=/usr/bin/env">>,<<"TEST=xxx">>,<<>>] %% Unset an "EMU" env variable: 11> f(Bin), {ok, [{stdout, [Bin]}]} = exec:run("env", [sync, stdout, {env, [{"EMU", false}]}]) , io:format("~s\n", [re:split(Bin, <<"\n">>)]). [...] ok %% Set an env variable to an empty string (use "" as the value, not false): 12> f(Bin), {ok, [{stdout, [Bin]}]} = exec:run("env", [sync, stdout, {env, [{"MY_VAR", ""}]}]), io:format("~s\n", [re:split(Bin, <<"\n">>)]). [..., <<"MY_VAR=">>, ...] ok ``` -------------------------------- ### Redirect OS Process stdout to File Source: https://hexdocs.pm/erlexec Demonstrates redirecting the standard output of an OS process to a file using the `stdout` option with a file path. The file content can then be read and the file deleted. ```erlang 7> f(I), {ok, _, I} = exec:run_link("for i in 1 2 3; do echo \"Test$i\"; done", [{stdout, "/tmp/output"}]). 8> io:format("~s", [binary_to_list(element(2, file:read_file("/tmp/output")))]), file:delete("/tmp/output"). Test1 Test2 Test3 ok ``` -------------------------------- ### Redirect OS Process stdout to Screen, Erlang Process, or Custom Function Source: https://hexdocs.pm/erlexec Shows various ways to handle OS process standard output: printing directly to the screen (`print`), sending to the current Erlang process (`self()`), or processing with a custom function. ```erlang 9> exec:run("echo Test", [{stdout, print}]). {ok,<0.119.0>,29651} Got stdout from 29651: <<"Test\n">> 10> exec:run("for i in 1 2 3; do sleep 1; echo \"Iter$i\"; done", [{stdout, fun(S,OsPid,D) -> io:format("Got ~w from ~w: ~p\n", [S,OsPid,D]) end}]). {ok,<0.121.0>,29652} Got stdout from 29652: <<"Iter1\n">> Got stdout from 29652: <<"Iter2\n">> Got stdout from 29652: <<"Iter3\n">> % Note that stdout/stderr options are equivanet to {stdout, self()}, {stderr, self()} 11> exec:run("echo Hello World!; echo ERR!! 1>&2", [stdout, stderr]). {ok,<0.244.0>,18382} 12> flush(). Shell got {stdout,18382,<<"Hello World!\n">> Shell got {stderr,18382,<<"ERR!!\n">> ok ``` -------------------------------- ### Include Erlexec in application configuration Source: https://hexdocs.pm/erlexec Add erlexec to the applications list in your *.app.src file. ```erlang {applications, [kernel, stdlib, % ... erlexec ]} ``` -------------------------------- ### Execute OS Command With PTY Source: https://hexdocs.pm/erlexec Run a command with a pseudo-terminal enabled for more interactive or terminal-like behavior. Includes 'sync', 'stdout', and 'pty' options. ```erlang % Execute a command with a pty 38> exec:run("echo hello", [sync, stdout, pty]). {ok,[{stdout,[<<"hello">>,<<"\r\n">>]}]} ``` -------------------------------- ### Execute Command with Custom PTY Options Source: https://hexdocs.pm/erlexec Run commands with specific pseudo-terminal configurations, such as setting the interrupt character (vintr). Use 'monitor' to observe process termination. Requires 'stdin', 'stdout', 'stderr', custom 'pty' options, and 'monitor'. ```erlang % Execute a command with custom pty options 46> {ok, P1, I1} = exec:run("cat", [stdin, stdout, {stderr, stdout}, {pty, [{vintr, 2}]}, monitor]). {ok,<0.199.0>,16662} 47> exec:send(I1, <<3>>). ok 48> flush(). ok 49> exec:send(I1, <<2>>). ok 50> flush(). Shell got {'DOWN',16662,process,<0.199.0>,{exit_status,2}} ok ``` -------------------------------- ### Configure build to use select(2) Source: https://hexdocs.pm/erlexec Set the USE_POLL environment variable to 0 to use select(2) instead of poll(2) for event demultiplexing. ```bash $ USE_POLL=0 make ``` -------------------------------- ### Kill OS Process with Signal Source: https://hexdocs.pm/erlexec Shows how to kill an OS process using `exec:kill/2` and inspect its exit status with `exec:status/1`. Linking to the process via `exec:run_link/2` will cause the Erlang shell to exit if the OS process is killed. ```erlang 1> f(I), {ok, _, I} = exec:run_link("sleep 1000", []). {ok,<0.37.0>,2350} 2> exec:kill(I, 15). ok ** exception error: {exit_status,15} % Our shell died because we linked to the % killed shell process via exec:run_link/2. 3> exec:status(15). % Examine the exit status. {signal,15,false} % The program got SIGTERM signal and produced % no core file. ``` -------------------------------- ### Use Custom Success Return Code Source: https://hexdocs.pm/erlexec Illustrates how to specify a custom success exit code for an OS process using the `success_exit_code` option. If the process exits with a different code, it will be returned as an error. ```erlang 1> exec:start_link([]). {ok,<0.35.0>} 2> exec:run_link("sleep 1", [{success_exit_code, 0}, sync]). {ok,[]} 3> exec:run("sleep 1", [{success_exit_code, 1}, sync]). {error,[{exit_status,1}]} % Note that the command returns exit code 1 ``` -------------------------------- ### Specify Custom Process Shutdown Delay Source: https://hexdocs.pm/erlexec Demonstrates how to set a custom `kill_timeout` for stopping an OS process that might ignore SIGTERM. The `exec:stop/1` function is used, and the process exit is monitored. ```erlang % Execute an OS process (script) that blocks SIGTERM with custom kill timeout, and monitor 22> f(I), {ok, _, I} = exec:run("trap '' SIGTERM; sleep 30", [{kill_timeout, 3}, monitor]). {ok,<0.399.0>,26347} % Attempt to stop the OS process 23> exec:stop(I). ok % Wait for its completion 24> f(M), receive M -> M after 10000 -> timeout end. {'DOWN',26347,process,<0.403.0>,normal} ``` -------------------------------- ### Interactive Command Execution with PTY Echo Source: https://hexdocs.pm/erlexec Execute interactive commands like 'cat' using pty echo for real-time input and output. Requires 'stdin', 'stdout', 'stderr', 'pty', and 'pty_echo' options. Use 'exec:send/2' to send input and 'flush/0' to process output. ```erlang % Execute a command with pty echo 39> {ok, P0, I0} = exec:run("cat", [stdin, stdout, {stderr, stdout}, pty, pty_echo]). {ok,<0.162.0>,17086} 40> exec:send(I0, <<"hello">>). ok 41> flush(). Shell got {stdout,17086,<<"hello">>} ok 42> exec:send(I0, <<"\n">>). ok 43> flush(). Shell got {stdout,17086,<<"\r\n">>} Shell got {stdout,17086,<<"hello\r\n">>} ok 44> exec:send(I, <<3>>). ok 45> flush(). Shell got {stdout,17086,<<"^C">>} Shell got {'DOWN',17086,process,<0.162.0>,{exit_status,2}} ok ``` -------------------------------- ### Execute OS Command Without PTY Source: https://hexdocs.pm/erlexec Use this to run a command without a pseudo-terminal, suitable for simple, non-interactive tasks. Requires 'sync' and 'stdout' options. ```erlang % Execute a command without a pty 37> exec:run("echo hello", [sync, stdout]). {ok, [{stdout,[<<"hello\n">>]}]} ``` -------------------------------- ### Add Erlexec as a dependency in Elixir Source: https://hexdocs.pm/erlexec Include the erlexec dependency in your mix.exs file. ```elixir defp deps do [ # ... {:erlexec, "~> 2.0"} ] end ``` -------------------------------- ### Add Erlexec as a dependency in rebar.config Source: https://hexdocs.pm/erlexec Include the erlexec dependency in your project's rebar.config file. ```erlang {deps, [% ... {erlexec, "~> 2.0"} ]}. ``` -------------------------------- ### Specify Custom Kill Command for Process Source: https://hexdocs.pm/erlexec Execute an OS process that blocks SIGTERM and uses a custom kill command (SIGINT). A monitor is added to wait for process exit notification. The special environment variable "CHILD_PID" is used by the kill command. ```erlang % Execute an OS process (script) that blocks SIGTERM, and uses a custom kill command, % which kills it with a SIGINT. Add a monitor so that we can wait for process exit % notification. Note the use of the special environment variable "CHILD_PID" by the % kill command. This environment variable is set by the port program before invoking % the kill command: 2> f(I), {ok, _, I} = exec:run("trap '' SIGTERM; sleep 30", [{kill, "kill -n 2 ${CHILD_PID}"}, {kill_timeout, 2}, monitor]). {ok,<0.399.0>,26347} % Try to kill by SIGTERM. This does nothing, since the process is blocking SIGTERM: 3> exec:kill(I, sigterm), f(M), receive M -> M after 0 -> timeout end. timeout % Attempt to stop the OS process 4> exec:stop(I). ok % Wait for its completion 5> f(M), receive M -> M after 1000 -> timeout end. {'DOWN',26347,process,<0.403.0>,normal} ``` -------------------------------- ### Send End-of-File to OS Process STDIN Source: https://hexdocs.pm/erlexec Send an explicit end-of-file (eof) atom to an OS process's STDIN to signal the end of input. This is useful for processes that need to detect when input is complete, such as when piping commands. ```erlang 2> Watcher = spawn(fun F() -> receive Msg -> io:format("Got: ~p\n", [Msg]), F() after 60000 -> ok end end). <0.112.0> 3> f(Pid), f(OsPid), {ok, Pid, OsPid} = exec:run("tac", [stdin, {stdout, Watcher}, {stderr, Watcher}]). {ok,<0.114.0>,26143} 4> exec:send(Pid, <<"foo\n">>). ok 5> exec:send(Pid, <<"bar\n">>). ok 6> exec:send(Pid, <<"baz\n">>). ok 7> exec:send(Pid, eof). %% <--- sending the EOF command to the STDIN ok Got: {stdout,26143,<<"baz\nbar\nfoo\n">>} ``` -------------------------------- ### Kill Process Group on Process Exit Source: https://hexdocs.pm/erlexec Ensure that a group of processes is terminated when a parent process exits. Use the 'kill_group' option and specify the process group ID (GID). Processes in the same group will receive SIGTERM. ```erlang % In the following scenario the process P0 will create a new process group % equal to the OS pid of that process (value = GID). The next two commands % are assigned to the same process group GID. As soon as the P0 process exits % P1 and P2 will also get terminated by signal 15 (SIGTERM): 51> {ok, P2, GID} = exec:run("sleep 10", [{group, 0}, kill_group]). {ok,<0.37.0>,25306} 52> {ok, P3, _} = exec:run("sleep 15", [{group, GID}, monitor]). {ok,<0.39.0>,25307} 53> {ok, P4, _} = exec:run("sleep 15", [{group, GID}, monitor]). {ok,<0.41.0>,25308} 54> flush(). Shell got {'DOWN',25307,process,<0.39.0>,{exit_status,15}} Shell got {'DOWN',25308,process,<0.41.0>,{exit_status,15}} ok ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.