From f3692124060058386d56d0c4aaa0d98f9fa5288a Mon Sep 17 00:00:00 2001 From: Frank Hunleth Date: Sat, 23 Mar 2019 22:50:03 -0400 Subject: [PATCH] Load modules from /etc/modules 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 could 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. --- README.md | 14 +++++----- lib/nerves_runtime/application.ex | 46 ++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 4a1d0b8..05dd351 100644 --- a/README.md +++ b/README.md @@ -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` @@ -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, diff --git a/lib/nerves_runtime/application.ex b/lib/nerves_runtime/application.ex index baf75bd..741a102 100644 --- a/lib/nerves_runtime/application.ex +++ b/lib/nerves_runtime/application.ex @@ -1,7 +1,10 @@ defmodule Nerves.Runtime.Application do @moduledoc false + @module_list "/etc/modules" + use Application + require Logger alias Nerves.Runtime.{ Init, @@ -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 = @@ -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, @@ -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" @@ -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