Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load modules from /etc/modules #131

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ information, see the [hex docs](https://hexdocs.pm/nerves_runtime).
## System Initialization

`nerves_runtime` provides an OTP application (`nerves_runtime`) that can
initialize the system when it is started. For this to be useful,
`nerves_runtime` must be started before other OTP applications, since most will
assume that the system is already initialized before they start. To set up
`nerves_runtime` to work with `shoehorn`, you will need to do the following:
initialize the system on boot. For this to be useful, `nerves_runtime` must be
started before other OTP applications, since most will assume that the system is
already initialized before they start. To set up `nerves_runtime` to work with
`shoehorn`, you will need to do the following:

1. Include `shoehorn` in `mix.exs`
2. Include `shoehorn` in your `rel/config.exs`
Expand All @@ -40,9 +40,9 @@ assume that the system is already initialized before they start. To set up

### Kernel Modules

`nerves_runtime` will attempt to auto-load kernel modules by calling `modprobe`
using the `modalias` supplied by the device's `uevent` message. You can disable
this feature by configuring `autoload: false` in your application configuration:
`nerves_runtime` loads kernel modules from the `/etc/modules` file and on
demand as devices are discovered by `uevent` messages. You can disable this
feature by configuring `autoload: false` in your application configuration:

```elixir
config :nerves_runtime, :kernel,
Expand Down
46 changes: 39 additions & 7 deletions lib/nerves_runtime/application.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
defmodule Nerves.Runtime.Application do
@moduledoc false

@module_list "/etc/modules"

use Application
require Logger

alias Nerves.Runtime.{
Init,
Expand All @@ -12,13 +15,6 @@ defmodule Nerves.Runtime.Application do
alias Nerves.Runtime.Log.{KmsgTailer, SyslogTailer}

def start(_type, _args) do
# On systems with hardware random number generation, it is important that
# "rngd" gets started as soon as possible to start adding entropy to the
# system. So much code directly or indirectly uses random numbers that it's
# very easy to block on the random number generator or get low entropy
# numbers.
try_rngd()

target = Nerves.Runtime.target()

children =
Expand All @@ -37,6 +33,9 @@ defmodule Nerves.Runtime.Application do
defp target_children(_target) do
kernel_opts = Application.get_env(:nerves_runtime, :kernel, [])

# Kick off startup tasks asynchronously
spawn(fn -> run_startup_tasks(kernel_opts) end)

[
KmsgTailer,
SyslogTailer,
Expand All @@ -45,6 +44,20 @@ defmodule Nerves.Runtime.Application do
]
end

defp run_startup_tasks(opts) do
# Auto-load hardcoded modules
if Keyword.get(opts, :autoload_modules, true) do
load_kernel_modules()
end

# On systems with hardware random number generation, it is important that
# "rngd" gets started as soon as possible to start adding entropy to the
# system. So much code directly or indirectly uses random numbers that it's
# very easy to block on the random number generator or get low entropy
# numbers.
try_rngd()
end

defp try_rngd() do
rngd_path = "/usr/sbin/rngd"

Expand All @@ -53,4 +66,23 @@ defmodule Nerves.Runtime.Application do
System.cmd(rngd_path, [])
end
end

defp load_kernel_modules() do
with {:ok, contents} <- File.read(@module_list) do
contents
|> String.split("\n")
|> Enum.map(&String.trim/1)
|> Enum.each(&process_modules_line/1)
end
end

defp process_modules_line(""), do: :ok
defp process_modules_line("#" <> _comment), do: :ok

defp process_modules_line(module_name) do
case System.cmd("/sbin/modprobe", [module_name]) do
{_, 0} -> :ok
_other -> Logger.warn("Error loading module #{module_name}. See #{@module_list}.")
end
end
end