Packages
nerves_runtime
0.3.0
0.13.13
0.13.12
0.13.11
retired
0.13.10
0.13.9
0.13.8
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.10
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
retired
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.1
0.3.0
0.2.0
0.1.2
0.1.1
0.1.0
Small, general runtime utilities for Nerves devices
Current section
Files
Jump to
Current section
Files
lib/nerves_runtime/shell/evaluator.ex
defmodule Nerves.Runtime.Shell.Evaluator do
@moduledoc """
The evaluator is responsible for managing the shell port and executing
commands against it.
"""
def init(command, server, leader, _opts) do
old_leader = Process.group_leader
Process.group_leader(self(), leader)
command == :ack && :proc_lib.init_ack(self())
path = System.find_executable("sh")
port = Port.open({:spawn_executable, path}, [:binary, :stderr_to_stdout, :eof, :exit_status])
state = %{port: port, path: path}
try do
loop(server, state)
after
Process.group_leader(self(), old_leader)
end
end
defp loop(server, state) do
port = state.port
receive do
{^port, {:data, data}} ->
IO.puts("#{data}")
loop(server, state)
{^port, {:exit_status, status}} ->
IO.puts("Interactive shell port exited with status #{status}")
:ok
{:eval, ^server, command, shell_state} ->
send(state.port, {self(), {:command, command}})
# If the command changes the shell's directory, there's
# a chance that this checks too early. In practice, it
# seems to work for "cd".
new_shell_state = %{shell_state | counter: shell_state.counter + 1,
cwd: get_cwd(port) }
send(server, {:evaled, self(), new_shell_state})
loop(server, state)
{:done, ^server} ->
send(port, {self(), :close})
:ok
other ->
IO.inspect(other, label: "Unknown message received by Nerves host command evaluator")
loop(server, state)
end
end
defp get_cwd(port) do
# Get the current working directory of the port via the Linux /proc mechanism
with {:os_pid, os_pid} <- Port.info(port, :os_pid),
{:ok, cwd} <- :file.read_link("/proc/#{os_pid}/cwd"),
do: cwd
end
end