# Example tree — boot scripts, globals, and actions

This directory ships reference SysV init wrappers, `vdevd.globals.json`, and action
snippets used on Debian/gnuinos installs. For per-action semantics see
**`actions/README.md`**. For end-to-end verification see **`how-to-test.md`** at the
repo root.

---

## Boot model (1.5.5+)

Two services; **`vdev`** does **not** wait on coldplug:

| Script | Install name | Role |
|--------|--------------|------|
| **`sysv-initscript.sh`** | **`/etc/init.d/vdev`** | Start **`vdevd.early`** (hotplug listener + control), or **`vdevd.conf`** if **`vdev.ready`** already exists |
| **`sysv-coldplug.sh`** | **`/etc/init.d/vdev-coldplug.sh`** | Oneshot: **`boot_vga`** KMS, then a **background** worker that seeds, settles, **promotes**, and sweeps sysfs |

Removed from the boot path (do not resurrect): **`vdev-modprobe`**, **`vdev-settle-sync`**, **`vdev-terminal-coldplug`**, **`hotplug_only` / `-H`**.

### Sequence

1. **`vdev`** starts **`vdevd -c vdevd.early.conf`** (netlink + **`/run/udev/control`**; no sysfs walk).
2. **`vdev-coldplug`** (background):
   - wait for control
   - **`vdevadm trigger -s …`** for **`profiles.early.subsystems`**
   - **`vdevadm settle`**
   - **`vdevadm control --promote[=long-running.conf]`** (same PID → **`vdevd.conf`** / **`actions`**)
   - **`touch vdev.ready`**
   - **`vdevadm trigger --sysfs`** (full `/sys/devices` sweep; not waited)
3. On **`vdev` restart** when **`vdev.ready`** exists → start long-running **`vdevd.conf`** directly.

```mermaid
sequenceDiagram
    participant Vdev as sysv-initscript
    participant VE as vdevd.early
    participant CP as sysv-coldplug_bg
    participant LR as vdevd.conf

    Vdev->>VE: early listener plus control
    CP->>CP: boot_vga KMS sync
    CP->>VE: wait control
    CP->>VE: trigger early subsystems
    CP->>VE: vdevadm settle
    CP->>VE: vdevadm control --promote
    Note over VE,LR: same PID loads long-running conf
    CP-->>CP: touch vdev.ready
    CP->>LR: vdevadm trigger --sysfs
```

### Promote (control socket)

Promote and reload use the control socket only (no SIGHUP fallback):

```sh
vdevadm control --promote
vdevadm control --promote=/etc/vdev/vdevd.conf
vdevadm control --reload
vdevadm control --print-pid          # listener PID via SO_PEERCRED
vdevadm control --exit               # ask listener to stop (VDEV_CTRL_EXIT)
```

Empty promote path → daemon uses **`profiles.long-running.config`** from JSON. Wire
types: **`VDEV_CTRL_PROMOTE`** (`buf` = path/basename), **`VDEV_CTRL_RELOAD`**,
**`VDEV_CTRL_EXIT`**. **`--print-pid`** does not send a wire message; it connects and
reads the peer PID with **`SO_PEERCRED`** (listeners only — **`coldplug_only`** does
not bind control).

A stray **`SIGHUP`** is ignored by **`vdevd`** (still blocked via signalfd so the
default disposition cannot kill the daemon). **`SIGINT`** (Ctrl+C) exits the poll
loop — useful when running **`vdevd -1`** / **`coldplug_only`** in the foreground for
tests (no control socket on that instance).

Coldplug tunables: **`VDEV_PROMOTE_RETRIES`** (default **5**), **`VDEV_LONG_RUNNING_CONFIG`**.

### What `vdevd` does vs scripts

| Concern | Owner |
|---------|--------|
| Subsystem seed order | JSON **`profiles.*.subsystems`** + **`vdevadm trigger -s`** (scripts) |
| Sysfs walk in C | Only **`coldplug_only=1`** (e.g. optional terminal **`vdevd.1 -1`**) |
| Promote / reload / stop | Control **`PROMOTE`** / **`RELOAD`** / **`EXIT`**; init **`stop`** uses **`vdevadm control --print-pid`** then **`SIGTERM`** |
| Ready stamps | **`vdev.ready`**: coldplug after promote; **`vdevd-1-coldplug.ready`**: **`os-queue-tracking.sh`** when **`queue_tracking_flag=2`** |

Daemon C globals load only **`sysfs`**, **`config-dir`**, and **`long_running`**. Scripts
still read **`subsystems`** / **`stamp`** from the same JSON via **`jq`**.

---

## Runtime stamps (`$VDEV_STAMP_DIR`, default `/run/vdev`)

| File | Writer | Meaning |
|------|--------|---------|
| **`vdev.ready`** | **`vdev-coldplug`** after successful promote | Long-running profile is in effect; **`vdev` restart** may start **`vdevd.conf`** directly |
| **`vdevd-1-coldplug.ready`** | **`os-queue-tracking.sh`** (flag **2**) | Optional terminal coldplug finished |

---

## Initramfs (`initrd`)

**`initramfs-tools/scripts/init-top/vdev`** starts **`vdevd`** with
**`vdevd.initrd.conf`** / **`actions.initrd`**, binds control, and seeds with
**`vdevadm trigger -s pci|block|usb -a add`** (order from JSON **`profiles.initrd.subsystems`**).
**`init-bottom`** stops the initrd listener with
**`kill -TERM "$(vdevadm control --print-pid)"`** before pivoting.

Kernel **`bind`/`unbind`** are treated like **`add`/`remove`** for late hotplug while
the initrd listener is up. Do **not** add driver rebind loops in initrd (that belongs
to real-root input tooling if needed).

---

## Comments in `vdevd.globals.json`

`vdevd` strips **`//` line** and **`/* */` block** comments outside JSON strings
(**`vdev_globals_json_strip_comments()`**). SysV wrappers often preprocess with
**`sed` + `jq`** — keep comments valid for both.

**`profiles.<name>.stamp`** values are **script-only**. **`vdevd`** uses INI
**`queue_tracking_flag`**, JSON **`config`** / **`long-running`** basenames, and
optional **`profiles.*.actions`** allowlists when loading **`*.act`** files.

Example layout (see **`vdevd.globals.json`** / **`debian/config/vdevd.globals.json`**):

```json
{
  "globals": {
    "sysfs": "/sys",
    "config-dir": "/etc/vdev",
    "states-stamp-dir": "/run/vdev"
  },
  "profiles": {
    "initrd": {
      "config": "vdevd.initrd.conf",
      "subsystems": ["pci", "block", "usb"],
      "actions": [
        "001-sysfs-block.act",
        "001-sysfs-char.act",
        "002-modalias.act",
        "char.act",
        "device-mapper.act"
      ]
    },
    "early": {
      "config": "vdevd.early.conf",
      "subsystems": ["graphics", "video4linux", "input", "hid", "i2c", "drm", "fd"],
      "stamp": "vdev.ready",
      "actions": [
        "002-modalias.act",
        "dri.act",
        "fb.act",
        "input.act",
        "seat.act",
        "uaccess.act",
        "v4l.act",
        "zzz-udev-compat.act"
      ]
    },
    "terminal": {
      "config": "vdevd.1.conf",
      "stamp": "vdevd-1-coldplug.ready",
      "actions": "*"
    },
    "long-running": { "config": "vdevd.conf", "actions": "*" }
  }
}
```

**`profiles.*.actions`:** basenames under that profile’s INI **`actions=`** directory
(or **`"*"`** / **`["*"]`** for every file there). A leftover **`*.act`** on disk
that is not listed is skipped at load / reload / promote — drop it from the JSON
instead of deleting files in **`postinst`**. Missing **`actions`** keeps the old
behaviour (load everything in the directory).

---

## Optional helpers (not on the default boot path)

- **`vdev_settle`** (`lib/vdev/vdev_settle`) — libinput seat0 monitor + FIFOs; usable via
  **`vdevadm settle --input`** / **`--input-worker`** for debugging, not required for
  promote.
- **`vdevd.1.conf` + `-1`** — optional terminal full-sysfs oneshot with
  **`queue_tracking_flag=2`**; post-promote **`--sysfs`** usually replaces it.

---

## Related files

| Path | Role |
|------|------|
| **`sysv-initscript.sh`** | **`vdev`** — early or long-running |
| **`sysv-coldplug.sh`** | **`vdev-coldplug`** — KMS + seed + **`control --promote`** + **`--sysfs`** |
| **`conf.mk` / `Makefile`** | Stage/install init scripts + actions |
| **`vdevd.globals.json`** | Globals, profiles, subsystem lists, **`actions`** allowlists |
| **`../tools/vdevadm/`** | CLI — see **`tools/vdevadm/README.md`** |
| **`actions/`** | Default long-running actions |

---

## See also

- **`actions/README.md`** — action fields, **`zzzz-os-queue-tracking`**
- **`how-to-test.md`** — globals reference, seat checks, audio
- **`tools/vdevadm/README.md`** — **`trigger`**, **`settle`**, **`control --promote`**, **`--print-pid`**
