# `Nerves.Runtime`
[🔗](https://github.com/nerves-project/nerves_runtime/blob/v0.13.12/lib/nerves_runtime.ex#L9)

Nerves.Runtime contains functions useful for almost all Nerves-based devices.

# `cmd`

```elixir
@spec cmd(binary(), [binary()], :debug | :info | :warn | :error | :return) ::
  {Collectable.t(), exit_status :: non_neg_integer()}
```

Run system command and log output into logger.

NOTE: Unlike System.cmd/3, this does not raise if the executable isn't found

# `firmware_slots`
*since 0.13.9* 

```elixir
@spec firmware_slots(Nerves.Runtime.FwupOps.options()) :: %{
  active: String.t(),
  next: String.t()
}
```

Return information about firmware slots

Most Nerves devices have two slots for firmware storage. The first slot is
usually labeled "a" and the second "b". Firmware updates alternate between
these slots. In principle, a Nerves system could define more slots for other
purposes.

This function returns a map with the how the firmware slots are currently
being used. It has the following keys:

* `:active` - the slot containing the currently running firmware
* `:next` - the slot containing the firmware that will be loaded on the next boot

If you're a Nerves systems developer, this function works best when
`Nerves.Runtime.FwupOps.status/1` is implemented. If not, a heuristic is used
that tends to mostly work if your Nerves system uses U-Boot variables to
track slots.

Normally options are not passed. See `t:Nerves.Runtime.FwupOps.options/0` for
modifying the behavior of `fwup`.

# `firmware_valid?`

```elixir
@spec firmware_valid?() :: boolean()
```

Return whether the firmware has been marked as valid

Prefer using `firmware_validation_status/0` since this function can't return
that whether the validation information is unknown due to errors or any other
reason.

For this function, "valid" means that the next boot will run the same firmware, so
it returns `true` if firmware validation isn't in use.

See `validate_firmware/0` for more information.

# `firmware_validation_status`
*since 0.13.9* 

```elixir
@spec firmware_validation_status() :: :validated | :unvalidated | :unknown
```

Return whether the running firmware slot has been validated

See `validate_firmware/0` for more information.

# `halt`

```elixir
@spec halt() :: no_return()
```

Halt the device (meaning hang, not power off, nor reboot).

Note: this is different than :erlang.halt(), which exits BEAM, and may end up
rebooting the device if `erlinit.config` settings allow reboot on exit.

# `mix_target`

```elixir
@spec mix_target() :: atom()
```

Return the mix target that was used to build this firmware

If you're running on the development machine, this will return `:host`.
If not, it will return whatever the user specified with the `MIX_TARGET`
environment variable when building this firmware.

# `poweroff`

```elixir
@spec poweroff() :: no_return()
```

Power off the device.

This calls `:init.stop/0` internally. If `:init.stop/0` takes longer than the
`erlinit.config`'s `--graceful-powerdown` setting (likely 10 seconds) then
the system will be hard rebooted.

# `reboot`

```elixir
@spec reboot() :: no_return()
```

Reboot the device and gracefully shutdown the Erlang VM.

This calls `:init.stop/0` internally. If `:init.stop/0` takes longer than the
`erlinit.config`'s `--graceful-powerdown` setting (likely 10 seconds) then
the system will be hard rebooted.

# `revert`

```elixir
@spec revert(Nerves.Runtime.FwupOps.options()) ::
  :ok | {:error, reason :: any()} | no_return()
```

Revert the device to running the previous firmware

This switches the active firmware slot back to the previous one and then
reboots. This fails if the slot is empty or partially overwritten to prevent
accidents. It also requires the revert feature to be implemented in the
Nerves system that's in use. See `Nerves.Runtime.FwupOps` for how this works.

Normally options are not passed. See `t:Nerves.Runtime.FwupOps.options/0` for
modifying the behavior of `fwup`.

Specifying `reboot: false` is allowed, but be sure to reboot. It's easy to
get confused if you don't reboot afterwards and do a double revert or
something else silly.

# `serial_number`

```elixir
@spec serial_number() :: String.t()
```

Return the device's serial number

Serial number storage is device-specific and configurable. Serial numbers can
be programmed in one-time programmable locations like in CPU ROM or
cryptographic elements. They can also be in rewritable locations like a
U-Boot environment block.

Nerves uses the [`boardid`](https://github.com/nerves-project/boardid/) by
default (set `:boardid_path` key in the application environment to another
program to override). Boardid uses the `/etc/boardid.config` file to
determine how to read the serial number. Official Nerves systems provide
reasonable default mechanisms for getting started. Override this file in your
application's `rootfs_overlay` to customize it.

This function never raises. If a serial number isn't available for any
reason, it will return a serial number of `"unconfigured"`.

# `validate_firmware`

```elixir
@spec validate_firmware(Nerves.Runtime.FwupOps.options()) :: :ok | {:error, any()}
```

Mark the running firmware as valid

A device cannot receive a new firmware if the current one has not been validated.
In the official Nerves systems, this typically happens automatically. If you are
handling the firmware validation in your app, then this function can be used as
a helper to mark firmware as valid.

For systems that support automatic reverting, if the firmware is not marked as
valid, then the next reboot will cause a revert to the old firmware

Normally options are not passed. See `t:Nerves.Runtime.FwupOps.options/0` for
modifying the behavior of `fwup`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
