Packages
nerves_runtime
0.6.4
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/kernel/uevent.ex
defmodule Nerves.Runtime.Kernel.UEvent do
use GenServer
require Logger
alias Nerves.Runtime.Device
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
def init(opts) do
autoload = if opts[:autoload_modules] != nil, do: opts[:autoload_modules], else: true
send(self(), :discover)
executable = :code.priv_dir(:nerves_runtime) ++ '/uevent'
port =
Port.open({:spawn_executable, executable}, [
{:args, []},
{:packet, 2},
:use_stdio,
:binary,
:exit_status
])
{:ok, %{port: port, autoload: autoload}}
end
def handle_info(:discover, s) do
Device.discover()
{:noreply, s}
end
def handle_info({_, {:data, <<?n, message::binary>>}}, s) do
msg = :erlang.binary_to_term(message)
handle_port(msg, s)
end
defp handle_port({:uevent, _uevent, kv}, s) do
event =
Enum.reduce(kv, %{}, fn str, acc ->
[k, v] = String.split(str, "=", parts: 2)
k = String.downcase(k)
Map.put(acc, k, v)
end)
case Map.get(event, "devpath", "") do
"/devices" <> _path -> registry(event, s)
_ -> :noop
end
{:noreply, s}
end
def registry(%{"action" => "add", "devpath" => devpath} = event, s) do
attributes = Map.drop(event, ["action", "devpath"])
scope = scope(devpath)
# Logger.debug "UEvent Add: #{inspect scope}"
if subsystem = Map.get(event, "subsystem") do
SystemRegistry.update_in(subsystem_scope(subsystem), fn v ->
v = if is_nil(v), do: [], else: v
[scope | v]
end)
end
if s.autoload, do: modprobe(event)
SystemRegistry.update(scope, attributes)
end
def registry(%{"action" => "remove", "devpath" => devpath} = event, _) do
scope = scope(devpath)
# Logger.debug "UEvent Remove: #{inspect scope}"
SystemRegistry.delete(scope)
if subsystem = Map.get(event, "subsystem") do
SystemRegistry.update_in(subsystem_scope(subsystem), fn v ->
v = if is_nil(v), do: [], else: v
{_, scopes} = Enum.split_with(v, fn v -> v == scope end)
scopes
end)
end
end
def registry(%{"action" => "change"} = event, s) do
# Logger.debug "UEvent Change: #{inspect event}"
raw = Map.drop(event, ["action"])
Map.put(raw, "action", "remove")
|> registry(s)
Map.put(raw, "action", "add")
|> registry(s)
end
def registry(%{"action" => "move", "devpath" => new, "devpath_old" => old}, _) do
# Logger.debug "UEvent Move: #{inspect scope(old)} -> #{inspect scope(new)}"
SystemRegistry.move(scope(old), scope(new))
end
def registry(event, _) do
Logger.debug("UEvent Unhandled: #{inspect(event)}")
end
defp scope("/" <> devpath) do
scope(devpath)
end
defp scope(devpath) do
[:state | String.split(devpath, "/")]
end
defp subsystem_scope(subsystem) do
[:state, "subsystems", subsystem]
end
defp modprobe(%{"modalias" => modalias}) do
System.cmd("modprobe", [modalias], stderr_to_stdout: true)
end
defp modprobe(_), do: :noop
end