Skip to content
Merged
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
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,14 @@ dmicmp_v4_send_echo_request(&dst, my_identifier, 1, NULL, 0, DMARP_DEFAULT_TIMEO

## Running as a service

dmicmp answers pings as soon as it's loaded, but being a Library-type
module it has no `main()` to spawn on its own - something still needs to
load it. **[configs/](configs/)** has a
[dmsystem](https://github.com/choco-technologies/dmsystem)/`libsystemd`
unit (`icmp.ini`) plus the two `dmell` scripts it runs
(`icmp-start.dme`/`icmp-stop.dme`, each a one-line `module load`/`module
unload dmicmp`) so ping response can be enabled at boot and toggled off
again. See [docs/service.md](docs/service.md) for the full setup and why
there's no `service stop icmp`.
dmicmp answers pings as soon as it's loaded and enabled, but being a
Library-type module it has no `main()` to spawn on its own - something still
needs to load it. **[configs/](configs/)** has a
[dmsystem](https://github.com/choco-technologies/dmsystem)/`libsystemd` unit
(`icmp.ini`, `exec=dmicmp` `type=library`) that registers dmicmp directly as a
service - no separate loader script needed. `service start icmp`/`service
stop icmp` load+enable / disable+unload it. See
[docs/service.md](docs/service.md) for the full setup.

## API

Expand Down Expand Up @@ -124,10 +123,8 @@ View documentation using `dmf-man dmicmp`.

```
dmicmp/
├── configs/ # dmsystem unit + dmell scripts to load/unload dmicmp as a service
│ ├── icmp.ini
│ ├── icmp-start.dme
│ └── icmp-stop.dme
├── configs/ # dmsystem unit (type=library) to register dmicmp as a service
│ └── icmp.ini
├── docs/ # Documentation (markdown format)
├── include/ # Public headers
│ └── dmicmp.h
Expand Down
18 changes: 0 additions & 18 deletions configs/icmp-start.dme

This file was deleted.

10 changes: 0 additions & 10 deletions configs/icmp-stop.dme

This file was deleted.

32 changes: 12 additions & 20 deletions configs/icmp.ini
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
# icmp.ini - dmsystem unit that loads the dmicmp module at boot, so this
# device starts answering ICMP Echo Requests (ping) with no manual step.
# Drop it into libsystemd's units directory - see dmsystem's configuration
# docs (https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md)
# - and make sure the path in "args" below is where this release's configs
# actually landed. The default matches the reference deployment (dmod-boot):
# it mounts its config filesystem at /configs and installs a module's
# untagged config entries under /configs/<module>/, so an unqualified
# `dmicmp icmp-start.dme` line in its flash.dmd puts the script exactly
# there. A placeholder that matches no deployment only looks configurable -
# it guarantees the unit fails on first boot. See ../docs/service.md.
# icmp.ini - dmsystem unit that loads and enables the dmicmp module at boot,
# so this device starts answering ICMP Echo Requests (ping) with no manual
# step. Drop it into libsystemd's units directory - see dmsystem's
# configuration docs (https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md#typelibrary-services-backed-by-a-library-module-not-a-process).
description=Answer ICMP Echo Requests (ping) by loading the dmicmp module
exec=dmell
args=/configs/dmicmp/icmp-start.dme
type=oneshot
exec=dmicmp
type=library

# type=oneshot: icmp-start.dme only needs to run once - dmicmp stays enabled
# and answering pings on its own once dmod_init() has run (see
# ../src/dmicmp.c), so there is no long-running process for this unit to
# keep alive. "service stop icmp" has nothing left to kill once this has run
# to completion - libsystemd has no ExecStop-style key yet - so to stop
# answering pings, run icmp-stop.dme directly instead (see ../docs/service.md).
# type=library: dmicmp is a Library-type DMOD module, not an Application - it
# has no main(), so it cannot be spawned as a process the way a "simple"/
# "oneshot" unit is. type=library tells libsystemd to load+enable "exec" as a
# module instead (the DMOD loader's own module lifecycle) when the unit is
# started, and to disable+unload it when the unit is stopped - see
# ../docs/service.md and dmsystem's configuration docs linked above.
5 changes: 3 additions & 2 deletions dmicmp.dmr
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ docs=./docs => ${destination}/${module}/docs [origin=${repo_dir}/docs]
readme=./README.md => ${destination}/${module}/README.md [origin=${repo_dir}/README.md]

# === Configuration Files ===
# icmp.ini dmsystem unit + icmp-start.dme/icmp-stop.dme dmell scripts that
# load/unload dmicmp to turn ICMP echo (ping) response on/off - see docs/service.md
# icmp.ini dmsystem unit (type=library) that loads/enables dmicmp to turn
# ICMP echo (ping) response on, and disables/unloads it on "service stop" -
# see docs/service.md
configs=./configs => ${destination}/${module}/configs [origin=${repo_dir}/configs]

# === Header Files ===
Expand Down
66 changes: 26 additions & 40 deletions docs/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,70 +6,56 @@ dmicmp needs no setup from other modules to do its core job - it registers
itself with [dmip](https://github.com/choco-technologies/dmip) automatically
in `dmod_init()` (see `src/dmicmp.c`), and from that point on answers ICMP
Echo Requests (ping) with no further calls needed. The catch is exactly that:
`dmod_init()` only runs once something *loads* dmicmp - nothing does that on
its own at boot. `configs/` gives
`dmod_init()` only runs once something *loads and enables* dmicmp - nothing
does that on its own at boot. `configs/icmp.ini` gives
[dmsystem](https://github.com/choco-technologies/dmsystem)'s `libsystemd` a
way to do it automatically.

## Why a `.dme` script instead of `exec=dmicmp` directly
## `exec=dmicmp`, `type=library`

dmicmp is a **Library**-type DMOD module (see `CMakeLists.txt`), not an
Application - it has no `main()`, so nothing can spawn it as a process the
way `libsystemd` starts a unit (`Dmod_RunModuleDetached`, see dmsystem's
[`app/libsystemd/docs/configuration.md`](https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md)).
way `libsystemd` starts a `simple`/`oneshot` unit (`Dmod_RunModuleDetached`).
What actually needs to happen is "load this module into the running DMOD
system", which is a different operation - the one
[`dmell`](https://github.com/choco-technologies/dmell) exposes as its own
`module load`/`module unload` built-in. `configs/icmp-start.dme` and
`configs/icmp-stop.dme` are two-line wrappers over exactly that, so a
`libsystemd` unit (whose `exec` must be something it can spawn) can drive
them the same way it drives any other unit.
system, then enable it" - `dmod_init()` (which is what actually registers
dmicmp with dmip) only runs on *enable*, not on load alone.

`libsystemd` supports this natively via `type=library` (named after
`Dmod_ModuleType_Library` in the dmod core): a unit with `type=library` has
its `exec` loaded and enabled (`Dmod_LoadModuleByName` + `Dmod_EnableModule`)
when started, and disabled and unloaded (`Dmod_DisableModule` +
`Dmod_UnloadModule`) when stopped - no separate launcher script needed,
unlike the process-spawning `simple`/`oneshot` types. See dmsystem's
[configuration docs](https://github.com/choco-technologies/dmsystem/blob/main/app/libsystemd/docs/configuration.md#typelibrary-services-backed-by-a-library-module-not-a-process)
for the full mechanism.

## Files

| File | Does |
|------|------|
| [`configs/icmp-start.dme`](../configs/icmp-start.dme) | `module load dmicmp` - starts answering pings. |
| [`configs/icmp-stop.dme`](../configs/icmp-stop.dme) | `module unload dmicmp` - stops answering pings. |
| [`configs/icmp.ini`](../configs/icmp.ini) | The dmsystem unit itself: `exec=dmell`, `args=<path to icmp-start.dme>`, `type=oneshot`. |

## Why `type=oneshot`, and why there is no "stop"
| [`configs/icmp.ini`](../configs/icmp.ini) | The dmsystem unit: `exec=dmicmp`, `type=library`. |

`icmp-start.dme` only needs to run once: unlike a `type=simple` unit (a
server expected to keep running until explicitly stopped), dmicmp stays
loaded - and answering pings - entirely on its own once `dmod_init()` has
run, independent of the script or process that triggered it. `type=oneshot`
tells `libsystemd` this exit is expected, not a crash (see dmsystem's
configuration docs, "Service type").
## `service start`/`service stop` both work

This does mean `service stop icmp` has nothing to act on: `libsystemd` stops
a unit by killing its tracked process
(`libsystemd_stop_service_internal()`), and a oneshot unit's process is
already gone by the time it would run. `libsystemd` also has no `ExecStop`-
style key yet - a unit file has no way to name a separate command to run on
stop. So turning ping response back off is a deliberate separate step, not
something `service stop icmp` does: run `icmp-stop.dme` directly.
Unlike the old `type=oneshot` + `.dme` script setup, `type=library` gives
`libsystemd` a real notion of "running" for this unit - `service status icmp`
reports it as running exactly while dmicmp is enabled, and `service stop
icmp` actually turns ping response off again (disables and unloads the
module), no separate script to run by hand:

```bash
dmell /opt/dmicmp/configs/icmp-stop.dme
service start icmp
service status icmp
service stop icmp
```

Whether dmicmp is currently answering pings or not is therefore controlled
entirely by which of the two scripts was last run - `module load`/`module
unload` are idempotent-safe either way (loading an already-loaded module or
unloading an already-unloaded one just fails harmlessly and is logged, it
does not crash the shell).

## Enabling at boot

Install dmicmp with its `.dmr` (see the root [README.md](../README.md)), then
drop `icmp.ini` into `libsystemd`'s units directory and point its `args` at
wherever `icmp-start.dme` was installed:
drop `icmp.ini` into `libsystemd`'s units directory:

```bash
cp /opt/dmicmp/configs/icmp.ini /etc/dmsystem/units/icmp.ini
# args= in icmp.ini must match the actual install path, e.g.:
# args=/opt/dmicmp/configs/icmp-start.dme
dmod_loader systemd.dmf --args "/etc/dmsystem/units"
```

Expand Down
Loading