Nerves.Runtime
Nerves.Runtime is a core component of Nerves. It contains applications and libraries that are expected to be useful on all Nerves devices. Here are some of its features:
- Generic system and filesystem initialization (suitable for use with bootloader)
- Introspection of Nerves system firmware and deployment metadata
- A custom shell for debugging and running commands in a
bash
shell like environment - Device reboot and shutdown
- A small Linux kernel
uevent
application for capturing hardware change events and more - More to come…
The following sections describe the features in more detail. For even more information, consult the hex docs.
System initialization
Nerves.Runtime provides an OTP application that can initialize the system when
it is started. For this to be useful, Nerves.Runtime must be started before
other OTP applications especially since non-Nerves-aware applications almost
certainly won’t know that they need this to work. Specific initialization is
detailed in other sections. To set Nerves.Runtime up with bootloader
, you will
need to do the following (luckily this should become easier as this new
functionality propagates through templates and examples.)
- Ensure that
bootloader
is included in yourmix.exs
and theBootloader.Plugin
is in yourrel/config.exs
. - In your
config/config.exs
, make sure that:nerves_runtime
is at the beginning of theinit:
list:
config :bootloader,
overlay_path: "",
init: [:nerves_runtime, :other_app],
app: :your_app
Kernel Modules
Nerves.Runtime will attempt to autoload kernel modules by calling modprobe
using the modalias
supplied from the uevent message for devices. You can
disable this feature by configuring autoload: false
in your application config.
config :nerves_runtime, :kernel,
autoload_modules: false
Filesystem initialization
Nerves systems generally ship with one or more application filesystem partitions. These are used for persisting data that’s expected to live between firmware updates. The root filesystem cannot be used since it is mounted read-only in Nerves.
Nerves.Runtime takes an unforgiving approach to managing the application partition: if it can’t be mounted read-write, it gets re-formatted. While filesystem corruption should be a rare event even on unexpected powerdowns with modern filesystems, Nerves devices may not be easily accessed to perform any kind of recovery. This allows for at least some functionality.
To verify that this recovery works, Nerves systems usually leave the application filesystems uninitialized so that the format operation happens on the first boot. This means that the first boot takes slightly longer than others.
Note that a common implementation of “reset to factory” defaults is to purposefully corrupt the application partition and reboot.
Nerves.Runtime uses firmware metadata to determine how to mount and initialize the application partition. The following variables are important:
[partition].nerves_fw_application_part0_devpath
- the path to the application partition. E.g.,/dev/mmcblk0p3
[partition].nerves_fw_application_part0_fstype
- the type of filesystem. E.g.,ext4
[partition].nerves_fw_application_part0_target
- where the partition should be mounted. E.g.,/root
or/mnt/appdata
Nerves system and firmware metadata
All official Nerves systems maintain a short list of key-value pairs for tracking the running firmware version, etc. and other system information. This information is not intended to be written frequently. To get this information, call one of the following:
Nerves.Runtime.KV.get_all_active/0
- return all key-value pairs associated with the actively running firmware.Nerves.Runtime.KV.get_active/0
- return all key-value pairs. This includes key-value pairs associated with the non-running firmware in an A/B partitioned system.Nerves.Runtime.KV.get_active/1
- look up the value of a key associated with the currently running firmware.Nerves.Runtime.KV.get/1
- look up the value of a key
Global Nerves metadata includes the following:
Key | Build env variable | Example value | Description —————————|——————————|————————|—————— nerves_fw_active | - | “a” | This key holds the prefix that identifies the actively running firmware metadata. In this example, all keys starting with “a.” hold information about the running firmware. nerves_fw_devpath | NERVES_FW_DEVPATH | “/dev/mmcblk0” | This is the primary storage device for the firmware.
Firmware-specific Nerves metadata includes the following. Note that the keys are
stored in the environment block prefixed by the firmware slot for which they
pertain. E.g., a.nerves_fw_description
is the description for the firmware in
the “A” slot.
Key | mix.exs project key | Build environment variable | fwup -m | Example value | Description ——————————————————|——————————-|——————————————————-|—————————-|————————-|———————- nerves_fw_application_part0_devpath | - | NERVES_FW_APPLICATION_PART0_DEVPATH | - | “/dev/mmcblkp3” | The block device that contains the application partition nerves_fw_application_part0_fstype | - | NERVES_FW_APPLICATION_PART0_FSTYPE | - | “ext4” | The application partition’s filesystem type (see the mount command for options) nerves_fw_application_part0_target | - | NERVES_FW_APPLICATION_PART0_TARGET | - | “/root” | Where to mount the application partition. nerves_fw_architecture | - | NERVES_FW_ARCHITECTURE | meta-architecture | “arm” | The processor architecture. Not currently used. nerves_fw_author | :author | NERVES_FW_AUTHOR | meta-author | “John Doe” | The person or company that created this firmware. nerves_fw_description | :description | NERVES_FW_DESCRIPTION | meta-description | “Stuff” | A description of the project nerves_fw_platform | - | NERVES_FW_PLATFORM | meta-platform | “rpi3” | A name to identify the board that this runs on. It can be checked in the fwup.conf before performing an upgrade. nerves_fw_product | :name | NERVES_FW_PRODUCT | meta-product | “My Product” | A product name that may show up in a firmware selection list, for example. nerves_fw_version | :version | NERVES_FW_VERSION | meta-version | “1.0.0” | The project’s version
As shown above, several keys can be set in the mix.exs
file or your main
Nerves project. That is also the preferred location of setting them. Assuming
that the fwup.conf
respects the fwup
variable names above, those are all
overridable by setting environment variables. Overriding the fwup.conf
provided by the Nerves system may be a preferrable way of setting them, though.
The fwup -m
column shows the key that you’ll see if you run
fwup -m -i <project.fw>
to extract the firmware metadata from the .fw
file.
Device reboot and shutdown
Reboot, poweroff, and halting a device work by signaling to
erlinit an intention to shutdown
and then exiting the Erlang VM by calling :init.stop/0
. The
Nerves.Runtime.reboot/0
and related utilities are helper methods for this.
Once they return, the Erlang VM will likely only be available momentarily before
shutdown. If the OTP applications cannot be stopped within a timeout as
specified in the erlinit.config
, erlinit
will ungracefully terminate the
Erlang VM.
The Nerves Runtime Shell
Nerves devices typically only expose an Elixir or Erlang shell prompt. While
this is handy, some tasks are quicker to run in a more bash
shell-like
environment. The Nerves runtime shell provides a limited approximation to this
that can be run without leaving the Erlang runtime. Here’s an example run:
iex(1)> [Ctrl+G]
User switch command
--> s sh
--> j
1 {erlang,apply,[#Fun<Elixir.IEx.CLI.1.112225073>,[]]}
2* {sh,start,[]}
--> c
Nerves Interactive Command Shell
Type Ctrl+G to exit the shell and return to Erlang job control.
This is not a normal shell, so try not to type Ctrl+C.
/srv/erlang[1]>
There are a few caveats to using this shell right now, so you’ll have to be careful when you use it:
Ctrl+C Ctrl+C
exits the Erlang VM and will reboot or hang your system depending on howerlinit
is configured.- Because of the
Ctrl+C
caveat, you can’t easily break out of long running programs. As a workaround, start another shell usingCtrl+G
andkill
the offending program. - Commands are run asynchronously. This is unexpected if you’re used to a regular shell. For most commands, it’s harmless. One side effect is that if a command changes the current directory, it could be that the prompt shows the wrong path.
Installation
The package can be installed
by adding nerves_runtime
to your list of dependencies in mix.exs
:
def deps do
[{:nerves_runtime, "~> 0.2.0"}]
end
Docs can be found at https://hexdocs.pm/nerves_runtime.