Skip to content

Commit

Permalink
Load modules from /etc/modules
Browse files Browse the repository at this point in the history
Auto-load modules listed in the `/etc/modules` file. This makes it
possible for systems to specify (and users to override) the load of
kernel modules that may not be detectable via `uevent` messages.

Previously these modules were compiled into the kernel, but this does
not support cases where they couple be optional. For example, it would
be nice to have a few USB gadget driver options without hardcoding them
into the kernel. This lets systems be made where the default case loads
a Ethernet/serial gadget driver (for example), but that can be disabled
by overriding `/etc/modules` with a different set of drivers.
  • Loading branch information
fhunleth committed Mar 24, 2019
1 parent 9e50a29 commit 04c0866
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 15 deletions.
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
47 changes: 39 additions & 8 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,12 +44,44 @@ defmodule Nerves.Runtime.Application do
]
end

defp try_rngd() do
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"

if File.exists?(rngd_path) do
# Launch rngd. It daemonizes itself so this should return quickly.
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

0 comments on commit 04c0866

Please sign in to comment.