# Changelog (English)

This document consolidates the history of the **vdev** upstream branch originally based on
[jcnelson/vdev](https://github.com/jcnelson/vdev)) and some built-in third-party 
libraries carried alongside the proyect within the `third-party` folder. No 
separate versioned changelog is shipped with that tree; treat them as upstream 
vendor code unless local commits say otherwise. 

---

## Third-party: uni-json

**uni-json** (“Universal Json”) is a small MIT-licensed C library by Rainer
Weikusat for parsing and serializing JSON while delegating memory management and
in-memory representation to the embedder. It lives under `uni-json/` in this
workspace (see `uni-json/README` and `uni-json/LICENSE`).

- **Scope:** Parser and serializer core in C; `make` produces `bin/libuni-json.a`
  and shared objects; install prefix from the `PREFIX` file (default
  `/usr/local`), honoring `DESTDIR`.

---

## Third-party: dmidecode-builtin

**dmidecode-builtin** is a minimal **GPL-2+** helper under `third-party/dmidecode-builtin/`. It prints the SMBIOS chassis type string (same semantics as `dmidecode -t chassis` filtered to the **Type** value) by reading Linux sysfs (`/sys/firmware/dmi/tables/*`) only. It links a **vendored** snapshot of dmidecode **util.c**, **util.h**, **types.h**, and **config.h** in **third-party/dmidecode-builtin/vendor/**.

- **Install name:** `lib/vdev/dmidecode-chassis-type-builtin` (see `VDEV_DMI_CHASSIS_BUILTIN` / `VDEV_DMI_CHASSIS_BUILTIN_DEFAULT` in `libvdev/dmi_chassis_builtin.h`).
- **Runtime:** `vdev` uses this helper first, then falls back to the `dmidecode` shell pipeline if the builtin produces no line.

---

## vdev (upstream fork — newest first)

Each section lists changes recorded in the upstream branch for that revision.

### vdev (1.4.7) — 9 Jul 2026

- **tools/vdevadm/**: New **`vdevadm`** CLI (udevadm-like) — **`info`**, **`trigger`**,
  **`settle`**, **`control`**, and **`monitor`**; linked against **libvdev**; **`monitor`**
  uses **libudev** / **libudev-compat** and is derived from eudev **`udevadm-monitor.c`**
  (Kay Sievers, GPL-2+). Legacy programs that invoke **`udevadm`** can use
  **`ln -sf vdevadm /usr/bin/udevadm`**; Debian **postinst** and the initramfs hook
  install that symlink when **`vdevadm`** is present. Project scripts call **`vdevadm`**
  directly (initramfs hook copies **`vdevadm`** only).
- **tools/vdevadm/**: **`trigger --name-prefix`** (e.g. **`event*`** on input);
  **`settle --list`**, **`--list-pending`**, **`--input`**, **`--input-worker`**
  (retrigger + libinput poll formerly in **`vdev-settle-sync.sh`**); **`control`**
  speaks eudev **`/run/udev/control`** (log level, exec queue, env, children-max).
- **libvdev/vdev_ctrl.c**, **vdevd**: eudev-compatible control socket at
  **`/run/udev/control`** (wire protocol from eudev **`udev-ctrl.c`**, Kay Sievers,
  LGPL-2.1+); **`/run/udev/queue`** for **`vdevadm settle`**; commands EXIT, RELOAD,
  PING, STOP/START_EXEC_QUEUE, SET_LOG_LEVEL, SET_ENV, SET_CHILDREN_MAX.
- **debian/vdev.vdev-settle-sync.sh**, **example/sysv-vdev-settle-sync.sh**: Simplified
  to JSON path setup plus **`vdevadm settle --stamp`**, **`--input-worker`**, and
  **`vdevadm control --stop-settle`** (~100 lines vs ~270).
- **vdevd/helpers/LINUX/dev-setup.sh**: **`eventfs_fstype_ok()`** accepts **`fuse`**,
  **`fuseblk`**, and **`fuse.*`** from **`stat -f '%T'`**; documents Devuan Excalibur
  reporting **`fuse`** only — avoids remounting a live eventfs queue and corrupting it.
- **vdevd/helpers/LINUX/udev-compat.sh**: Merge **`udisks-props`** (from **`udisks2.sh`**) into
  libudev-compat device DB records via **`udev_enumerate_udisks_properties()`**, so
  **`E:UDISKS_*`** / **`E:ID_FS_*`** reach **`/dev/metadata/udev/data/*`** for
  **`vdevadm`**, **udisks2**, and **gvfs** (Thunar / PCManFM), not only the synthetic
  uevent stream.
- **vdevd/helpers/LINUX/udisks2.sh**: Fix SSD / block visibility — stop hiding every
  partition on the root disk via **`vdev_root_sys_block`** sysfs cross-checks; set
  **`UDISKS_IGNORE=1`** only for whole disks (**`DEVTYPE=disk`**) or zero-size nodes
  (except optical **`sr*`**). Use **`$VDEV_MOUNTPOINT/disk/by-uuid`** for UUID lookup.
  Also ignore MBR extended/container partitions (**`0x05`**, **`0x0f`**, **`0x85`**) and
  other special DOS/GPT types mirrored from **`80-udisks2.rules`**, so a ~1K extended-
  partition node is not exported as a mountable volume (fixes udisks2/gvfs when logical
  partitions sit behind an MBR extended container).  Read filesystem UUIDs with
  **`vdev_blkid`** on the device node instead of scanning **`/dev/disk/by-uuid/`**.
  Keep **`sr*`** optical drives and **removable** whole-disk USB media visible;
  exempt hybrid ISO installer sticks (DOS **`0x0`/`0x17`** + **`iso9660`/`udf`**).
  **`/etc/fstab`** clone detection: parse Debian install comments (`# / was on
  `/dev/sda1` during installation`) before **`UUID=`** lines — the install device
  gets **`UDISKS_IGNORE=1`**, duplicate UUIDs on other nodes (Clonezilla clones)
  stay visible with **`UDISKS_IGNORE=0`**.
- **vdevd/helpers/LINUX/subr.sh**: Do not overwrite existing **`/dev/disk/by-uuid`**,
  **`by-partuuid`**, or **`by-label`** symlinks when a Clonezilla clone reuses the same
  IDs as the system disk — prevents alias hijacking that confused udisks2/gvfs.
- **vdevd/helpers/LINUX/vdev_root_sys_block.c**: Do not strip the namespace index from
  bare NVMe names (**`nvme0n1`** → **`nvme0n`**) when resolving the root block device.

### vdev (1.4.6) — 28 Jun 2026

- **`example/sysv-initscript.sh`**: Pick **`vdevd.1.conf`** vs **`vdevd.conf`** 
  from a live eventfs mount on **`metadata/udev/events/serial`**
  (`fuse` / `fuseblk` / `fuse.*` via `stat -f '%T'` + `ls`). If the serial queue
  is already mounted, treat **`start`** as a **`vdev restart`** and run
  long-running **`vdevd.conf`** only (skip the second **`vdevd.0`** coldplug pass
  and phased subshells).
- **vdevd/helpers/LINUX/dev-setup.sh**: Own the libudev-compat eventfs lifecycle:
  `eventfs_prepare_udev_layout`, health check (`fuse` / `fuseblk` / `fuse.*` via
  `stat -f '%T'` + `ls`), and background `setsid` mount on preseed. Skip remount
  when the serial queue is already healthy; do not unmount on `vdev` stop or
  restart
- **vdevd/helpers/LINUX/vdev-eventfs-umount.sh**: Unmount serial eventfs on system
  shutdown only (SysV runlevels 0/6)

### vdev (1.4.5) — 16 Jun 2026

- **`uaccess.sh`:** Call **`elogind-uaccess-command`** with the device node path **only**.
  **elogind 255.x** **`parse_argv()`** accepts one positional argument; passing
  **`seat0`** as a second argument logged **`Usage: elogind-uaccess-command DEVPATH
  [SEAT]`** on every **`uaccess`** device during coldplug. Seat defaults to
  **`seat0`** inside the binary when omitted.

### vdev (1.4.4) — 31 May 2026

- **`example/actions/README.md`:** Document single-argument **`elogind-uaccess-command`**
  invocation.

### vdev (1.4.3) — 31 May 2026

- **ALSA / desktop audio (eudev parity):** Ship vdev actions and helpers equivalent to udev **`60-persistent-alsa.rules`**, **`70-uaccess.rules`**, **`71-seat.rules`** (partial), **`78-sound-card.rules`**, and **`90-alsa-restore.rules`**: **`sound-alsa-control.act`**, **`70-sound-uaccess.act`**, **`78-sound-card-control.act`**, **`78-sound-card.act`**, **`90-alsa-restore.act`**; helpers **`sound.sh`**, **`sound-card.sh`**, **`alsa-restore.sh`**, **`audio-acl.sh`**; **`dev-setup.sh`** static **`snd/seq`** / **`snd/timer`** nodes; default **`/etc/asound.conf`** from **`debian/vdev-asound-analog.conf`**.
- **`udev-compat.sh`:** Emit core udev DB fields (**`E:DEVNAME`**, **`E:SUBSYSTEM`**, **`E:DEVPATH`**, **`E:MAJOR`**, **`E:MINOR`**) so elogind can sync session ACLs on **`snd/*`** at login (fixes sandboxed browsers without **apulse**); normalize **`E:DEVNAME`** to **`/dev/...`** paths.
- **`uaccess.sh`:** On **`snd/*`**, tag **`uaccess`**, set **`VDEV_SEAT`**, run **`elogind-uaccess-command`**, then **`audio-acl.sh`** fallback (vdev has no udev **`RUN`** hook for **`73-seat-late.rules`**).
- **`check-seat-udev.sh`:** Verify sound **`uaccess`** records include **`E:DEVNAME=/dev/snd/...`**.
- **`example/test-alsa-actions.sh`**, **`example/test-browser-audio.sh`:** Regression helpers for ALSA helpers and browser ACL/udev DB checks.
- **`how-to-test.md`**, **`example/actions/README.md`:** Document ALSA modprobe/**`asound.conf`**, action chain, and verification steps.
- **Removed **`72-sound-acl.act`**** (duplicate of **`70-sound-uaccess.act`** + **`uaccess.sh`** calling **`audio-acl.sh`**).
- **how-to-test.md**: Xlibre input hotplug — fix is **`startx`** + **`~/.xinitrc`**, not
  **`/etc/X11/Xsession`**; same **`exec`** from TTY without **`startx`** breaks hotplug;
  **`XDG_SESSION_TYPE=x11`** is not the cause.
- **uaccess.act** (`actions.1` + `example/actions`): Add `input/event*` to the path regex and `uaccess.sh` group mapping (aligns with systemd `70-uaccess` / elogind session ACLs on evdev nodes).

### vdev (1.4.2) — 27 May 2026

- **Phase-2 reload timing:** Drop fanotify `login`/`sleep(3)`/`SIGHUP` reload. Run `vdevd.2.conf` coldplug from the SysV `subshell` after `vdevd-1-coldplug.ready`, then `vdevd -k` and `exec` long-running `vdevd.conf` (fixes VT ACL loss on login and OpenRC stop errors while phase 2 is still running).
- **Phase-2 coldplug:** `if_exists=run` on `char.act`, `001-sysfs-char.act`, `dri.act`, `seat.act`, `tty.act`, `ttyN.act`, and `uaccess.act`; add `tty[0-9]+` to `uaccess` paths for elogind-style session ACLs on the active console.
- **Seat / seatd (phase 1 udev DB):** `debian/config/actions.1/zzz-udev-compat.act` no longer limits `udev-compat.sh` to `OS_SUBSYSTEM=input`, so DRM (and other phase-1 devices) get `G:seat`, `E:ID_SEAT=seat0`, and tag-index entries during `vdevd.1` coldplug — required for `seatd`, `libudev`, and `libinput` `seat0` without `xserver-*-legacy` SUID.
- **vdevd/helpers/LINUX/seat.sh**, **seat.act:** Emit `VDEV_SEAT=seat0` (udev `E:ID_SEAT`); extend matches to `fb[0-9]+` with `seat` tag and `master-of-seat` on `fb0` or hwdb `ID_TAG_MASTER_OF_SEAT=1` (`60-seat.hwdb`).
- **vdevd/helpers/LINUX/dev-setup.sh:** Create `/run/udev` → `/dev/metadata/udev` when `/run` exists and the symlink is missing (initramfs `init-top/vdev` already did this; real-root boot did not).
- **uaccess.act** (`actions.1` + `example/actions`): Include **`dri/renderD*`** in the path regex (logind-style `uaccess` tag).
- **vdevd/helpers/LINUX/check-seat-udev.sh:** New regression helper — waits for `vdevd-1-coldplug.ready`, then checks `/run/udev`, DRM/fb permissions, and udev-compat `data/` / `tags/seat/` records. Documented in `how-to-test.md`.
- **vdevd/helpers/LINUX/vdev_settle.c**: Rework settle helper as a libinput `seat0` monitor daemon that tracks input devices in `sglib` vectors and publishes shell-facing runtime state under `/run/vdev` (`vdev-settle.status`, `vdev-settle.seen`, `vdev-settle.pending`, `vdev-settle.pid`).
- **vdevd/helpers/LINUX/vdev_settle.c**: Add optional FIFO control plane (`vdev-settle.ctl` / `vdev-settle.rsp`) with commands `status`, `list`, `list-pending`, `reload`; support `SIGUSR1` refresh, `SIGHUP` metadata reload, and `SIGTERM`/`SIGINT` shutdown.
- **vdevd/helpers/LINUX/vdev_settle.**: Store seen entries as `eventN<TAB>libinput-name` (via `libinput_device_get_sysname()` + name), keep metadata optional, and report `seen N` when no expected-name list is provided.
- **example/sysv-vdev-settle-sync.sh`**: Replace passive stamp wait with a detached settle worker that starts `vdev_settle`, retriggers input `add` uevents for `/sys/class/input/event*`, logs successful retriggers to `vdev-settle.retriggered` and failures to `vdev-settle.trigger-failed`, then touches settle stamp and sends `SIGTERM` to `vdev_settle`.
- **example/sysv-vdev-settle-sync.sh**, **example/sysv-initscript.sh**: Drop redundant `VDEV_SETTLE_STAMP` / `globals.settle-stamp`; synchronize on coldplug stamps (`vdevd-0` / `vdevd-1`, `QUEUE_TRACKING_FLAG` 1/2) only. Settle worker waits `VDEV_EARLY_STAMP` plus `VDEV_SETTLE_VDEVD_DELAY` (default `0.5s`) before input retrigger.
- **Boot coldplug**: Drop the second early sysfs sweep (`VDEV_EARLY_PASS_SKIP`, early-pass manifest/index helpers, and related sysfs/netlink/fanotify branches). Input settle is handled by `vdev_settle` + `vdev-settle-sync` instead of a duplicate `vdevd.1` coldplug pass.
- **vdevd/device.c**: Stop propagating `VDEV_EARLY_PASS_SKIP` / `VDEV_EARLY_PASS_MANIFEST` into the synthesized helper environment.
- **libvdev/Makefile**, **vdevd/helpers/LINUX/Makefile**: Compile `helpers/LINUX/common.c` once into `libvdev.a** (`vdev-helpers-common.o`); helpers no longer leave `common.o` in `build/lib/vdev/`.
- **vdevd/helpers/LINUX**: Remove obsolete helper programs (`vdev_bind_input_devices`, `vdev_print_input_devices`, `vdev_reset_usb_devices`, `vdev_init_bottom`, `vdev_init_top`, `vdev_modprobe`, `vdev_modprobe_async`) and the shared include `vdev_modprobe_sysfs.inc`.
- **Packaging/build deps**: Stop installing removed helper binaries in `debian/install`; drop `libevdev-dev` from Debian `Build-Depends` and remove `libevdev` flags from the helper build.
- **vdevd/helpers/LINUX/vdev-ensure-eventfs.sh**, **dev-setup.sh**: Detect stale or dead FUSE on `metadata/udev/events/serial`, lazy-unmount and remount only when not live; start `eventfs` synchronously under `setsid` (no background `&`). `fs/README.md`: clarify that `user.eventfs_sticky` is a client-side xattr on `serial/libudev-<pid>-<slot>/`, not a vdev mount fix.

### vdev (1.4.1) — 10 May 2026

- **vdevd/os/linux_sysfs.inc**: For early sysfs second sweep `(VDEV_EARLY_PASS_SKIP=1)`, add an early prefilter pass in `vdev_linux_sysfs_register_devices()` that drops queued `uevent` paths already present in the first-pass index before subsystem queueing.
- **vdevd/os/linux_sysfs.inc**: Normalize skip comparisons so entries match with or without `/sys` prefix, and align default early-pass index path with manifest usage (`/dev/metadata/udev/early-pass.manifest`).
- **vdevd/os/linux_sysfs.inc**, **vdevd/device.c**, **vdevd/helpers/LINUX/os-early-manifest.sh**: Keep `VDEV_EARLY_PASS_IDX` and `VDEV_EARLY_PASS_MANIFEST` compatible across coldplug filtering and helper environment propagation, preserving second-pass test output in `_1` manifest variants.
- **vdevd/os/linux_sysfs.inc**: If `VDEV_EARLY_PASS_SKIP` leaves no devices to queue (i.e. `reg_q` empty) but `queue_tracking_flag` is non-zero, emit `QUEUE_TRACKING_FLAG` using a stable sysfs carrier `(devices/virtual/mem/null/uevent`, else `devices/system/cpu/cpu0/uevent)` so `os-queue-tracking.sh` still runs (stamp + optional `SIGTERM`).
- **vdevd/helpers/LINUX/os-queue-tracking.sh**: Use `case` / `${VDEV_COLDPLUG_ONLY:-0}` so `dash` does not error when `VDEV_EARLY_PASS_SKIP` or coldplug-only are unset.
- **vdevd/os/linux.c**: With `VDEV_EARLY_PASS_SKIP` set, do not create the `NETLINK_KOBJECT_UEVENT` socket (parent `vdevd` subshell already owns it); coldplug still runs from sysfs and `poll(2)` ignores the disabled netlink slot (`fd == -1`).
- **libvdev / config.c / config.h**: Remove the `netlink` INI key and `-N` / `--netlink` (compat events are eventfs-only; system **libeudev** owns netlink).
- **vdevd/device.c**, **daemonlet**: Drop `VDEV_EVENTFS` from the synthesized helper environment.
- **vdevd/vdev.c**, **vdevd/helpers/LINUX/dev-setup.sh**: Preseed is invoked as `preseed mountpoint config` only (no leading event-backend flag); `dev-setup.sh` mounts `eventfs` whenever the serial events path is not already FUSE-backed.
- **vdevd/helpers/LINUX/udev-compat.sh**: Always `event-put` to the compat queues; remove the `nl_monitor` fallback.
- **vdevd/os/linux.c**: Open `fanotify` only for the `primary early` instance: `vdev_linux_profile_is_early_sysfs`, not `coldplug_only`, `VDEV_EARLY_PASS_SKIP` unset (second sysfs sweep skips fanotify entirely). Other phases (modprobe, initrd, long-running, …) no longer install a fanotify fd.
- **vdevd/os/linux.c**: `fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_TID)` when the kernel accepts it (fallback without `FAN_REPORT_TID` + `vdev_warn`); track whether opener PID is available for the hand-off path.
- **vdevd/os/linux_events.inc**: On `FAN_OPEN` of the `vdevd` binary, drop `netlink` only when `vdev_linux_profile_has_reload`, `metadata->pid` is valid, `/proc/$pid/cmdline` shows `-H` and `-c` …/`globals.long_running`, and `/proc/$pid/environ` lacks truthy `VDEV_EARLY_PASS_SKIP` (filters the init second sweep’s `exec vdevd`). Removed the redundant in-handler “self” `VDEV_EARLY_PASS_SKIP` guard now implied by init policy.

### vdev (1.4.0) — 2 May 2026

- **vdevd/vdev_globals_json.c**: Before field extraction, `vdev_globals_json_strip_comments()` removes `//` line comments and `/* */` block comments **outside** JSON strings (string escapes honored), matching the intent of common `sed` preprocessing while remaining safe for multi-line blocks and literals like `"http://…"`. `vdevd` does not fork `sed`/`jq`.
- **vdevd/device.c**: Inject `VDEV_GLOBALS_JSON` and `VDEV_JSON_STATE` into the synthesized `env[]` passed to helper `execle` (async path uses `clearenv()`; wrappers’ exports would otherwise be invisible to helpers).
- **debian/config/vdevd.globals.json**, `example/vdevd.globals.json`: `globals.stamp_dir`, `globals["vdev-settle-ready"]` (settle stamp basename); `states.early.reload` as an object `{ "config", "stamp" }` (reload INI basename plus optional coldplug stamp name for `jq` tooling).
- **vdevd/helpers/LINUX/os-queue-tracking.sh**: Resolve stamp and directory via `jq` from `VDEV_CONFIG_FILE` matched against `.config` or `.reload.config`; `QUEUE_TRACKING_FLAG` `|1|/|2|` touch, `|3|` `SIGTERM` to parent.
- **SysV scripts**: Read `globals.stamp_dir` into `VDEV_COLDPLUG_STAMP_DIR`; settle basename from `globals["vdev-settle-ready"]` with fallback to legacy `.stamps["vdev-settle-ready"]`; `VDEV_SETTLE_STAMP` under that directory.
- **READMEs**: `example/README.md` — comments section and relation to shell preprocessors; `example/actions/README.md` — queue-tracking, `VDEV_GLOBALS_JSON`, helper env; `how-to-test.md` — Appendix **C** comments and globals reference.
- **Documentation**: Clarify that JSON `stamp` / `stamp_dir` are **script/orchestration only**; `vdevd` relies on JSON `config` / `reload.config` basenames and `[vdev-config] queue_tracking_flag` in each profile INI.
- **vdevd/vdev_globals_json.c**, **vdevd/vdev_globals_json.h**, **vdevd/vdev.c**: Move reload semantics to per-state full config targets (`states.<state>.reload`), so `SIGHUP` reload loads a complete config file (for example `vdevd.2.conf`) instead of patching selected fields.
- **example/vdevd.globals.json**: Model phase-2 with `states.early.reload: "vdevd.2.conf"` while keeping phase-1 state selection (`config`, `subsystems`, `stamp`) in the same state object layout.
- **example/README.md**: New documentation for reload semantics, startup rationale (mixed early phase, then coldplug-only reload), TRACKING_FLAG handoff timing, coexistence with long-running hotplug-only process, plus ASCII and Mermaid startup diagrams.
- **vdevd/main.c**, `vdevd/os/linux_events.inc`, `vdevd/vdev.c`: Keep reload control-plane ownership in `main.c`: Linux backend signals reload need (`SIGHUP`) based on per-state `reload` presence, while `main.c` performs the mutex-guarded config/action swap and full stop/rebuild/start sequencing using the reload config file for the active state.
- **Packaging/script alignment**: Keep helper install path as `vdev_settle` and retain settle/settle-sync naming consistency across SysV and packaging references.
- **vdevd/os/linux.c**, **vdevd/os/linux_events.inc**: Do not open a fanotify FD in the `long-running` profile; keep fanotify limited to early-stage handoff paths.
- **vdevd/helpers/LINUX/vdev_settle.c**, **vdevd/helpers/LINUX/Makefile**: Rename helper artifact from `vdev_wait` to `vdev_settle`.
- **example/vdevd.globals.json**: Rename settle stamp key/value to `stamps.vdev-settle-ready` with filename `vdev-settle.ready`.
- SysV script **example/sysv-initscript.sh**: Replace `x11`-named settle variables/messages with neutral `settle` naming.
- Sync script rename: **example/sysv-vdev-x11-sync.sh** -> **example/sysv-vdev-settle-sync.sh**, plus matching updates in `example/conf.mk`, and `example/Makefile`.

### vdev (1.3.99) — 30 Apr 2026

- **example/vdevd.globals.json**: Changed `vdevd.globals.json` layout: coldplug ready-marker `filenames` live under `states.modprobe.stamp` and `states.early.stamp`; the top-level `stamps` object carries `x11-sync-ready` only (helper / `vdev_wait` completion).
- **example/sysv-initscript.sh**, **example/sysv-modprobe.sh**: Read marker names from per-state `.stamp` when the state value is an object; otherwise fall back to `stamps.modprobe-coldplug-ready / stamps.early-coldplug-ready` for older `vdevd.globals.json` layouts.
- **example/vdevd.globals.json**: Changed `vdevd.globals.json` layout (each state is an object with `config` and optional `subsystems`; reload metadata lives under the target state object; shipped modprobe state uses `vdevd.1.conf` alongside early).
- **vdevd/vdev.h**, **vdevd/vdev_globals_json.c**: Add `globals.modprobe` (modprobe-phase config basename, default `vdevd.0.conf`). Parse `globals` object keys, `states.`* as either a string or `{ "config", "subsystems"? }`, load `states.modprobe`, keep compatibility with legacy `early-coldplug` naming for phase-2 selection, and retain legacy top-level `subsystems` and flat `states` strings when present.

### vdev (1.3.98) — 29 Apr 2026

- **vdevd/os/linux_sysfs.inc**, **vdevd/os/linux_events.inc**, **vdevd/main.c**: Select sysfs coldplug subsystem queues and fanotify behavior using `globals.modprobe / globals.early` instead of a hardcoded `vdevd.0.conf` basename; when both profiles share the same basename, use the environment variable `VDEV_JSON_STATE` (`modprobe` vs `early`) so `main.c` SIGHUP reload and sysfs registration stay consistent.
- **example/sysv-initscript.sh**, **example/sysv-modprobe.sh**: Resolve `states.early`, `states.long-running`, and `states.modprobe` via `jq` whether the value is a string or an object (`.config`); `export VDEV_JSON_STATE=modprobe` before the modprobe `vdevd` invocation, `export VDEV_JSON_STATE=early` (or `unset`) around the main init `vdevd` start and before `exec` into `long-running`.
- **vdevd/os/linux_sysfs.inc**: Fix discarded-qualifier compiler warnings by using mutable temporary pointers in `vdev_linux_sysfs_fullpath()` and `vdev_linux_uevent_append()` where returned buffers are later freed/reallocated.
- **vdevd/helpers/LINUX/stat_scsi.c**: Fix helper build failure (`else without a previous if`) in `scsi_dump_sense()` by replacing the fragile `if/else` logging branch with explicit braced conditionals.
- **vdevd/Makefile**: Restore helper artifact generation during standard builds by making `helpers` call `helpers/LINUX all`, so `make build` repopulates `build/lib/vdev/` binaries and scripts.
- **vdevd/helpers/LINUX/vdev_bind_input_devices.c**, **vdevd/helpers/LINUX/vdev_modprobe.c**, **vdevd/helpers/LINUX/vdev_wait.c**: Align sysfs fallback behavior so failure to resolve mountpoint via `get_sysfs_path()` now falls back to `/sys` instead of aborting.
- **vdevd/helpers/LINUX/stat_path.c**, **vdevd/helpers/LINUX/stat_net.c**: Add sysfs mountpoint autodetection via `get_sysfs_path()` (with `/sys` fallback) and replace hardcoded `"/sys"` path usage in subsystem/path lookup flows.
- **vdevd/helpers/LINUX/hwdb.sh**: Read sysfs mountpoint from `VDEV_GLOBALS_JSON` (`.globals.sysfs`, with fallback `.sysfs`) and default to `/sys` when not set.

### vdev (1.3.97) — 29 Apr 2026

- **vdevd/helpers/LINUX/vdev_print_input_devices.c**: Accept optional input metadata output filename as CLI argument (fallback `/dev/metadata/udev/input`).
- **vdevd/helpers/LINUX/vdev_wait.c**: Accept optional metadata filename argument and add `--quiet / -q` to suppress stdout device-name printing.
- **example/sysv-initscript.sh**: Pass `VDEV_INPUT_METADATA_FILE` to both helpers and call `vdev_wait` in quiet mode.
- **example/vdevd.globals.json**: Add `stamps` object for role-based SysV marker filenames (`modprobe-coldplug-ready`, `early-coldplug-ready`, `x11-sync-ready`).
- **example/sysv-initscript.sh**: Read `stamps.*` via `jq` and use them when selecting/waiting/removing coldplug `*.ready` markers.
- **example/sysv-modprobe.sh**: Use `stamps.modprobe-coldplug-ready` for phase-0 ready marker cleanup.
- **example/sysv-vdev-x11-sync.sh**: Build X11 sync stamp path from `stamps.x11-sync-ready` (with defaults).
- **example/sysv-initscript.sh**: Read nested globals JSON keys (`.globals.*`, `.states.*`) with fallback to legacy flat keys for compatibility.
- **example/sysv-modprobe.sh**: Stop hard-coding `/etc/vdev/vdevd.0.conf`; resolve `config-dir` and `states.modprobe` from `vdevd.globals.json` via `jq`.

### vdev (1.3.96) — 29 Apr 2026

- **fs/fs.c**: Fix critical `mknodat()` call argument order to `(dirfd, path, mode, dev)`.
- **fs/acl.c**: Fix ACL predicate execution by passing `proc_predicate_cmd` into `vdev_subprocess()` (previously `NULL`) and returning `-ENOMEM` on allocation failure.
- **fs/acl.c**: Correct ACL sanity validation to check `setuid / setgid` target IDs instead of source match IDs.
- **fs/fs.c**: Return actual status from `vdev_get_mountpoint()` and fix route-registration error guard for `fskit_route_mknod()` (`rh` vs `rc`).
- **fs/acl.c**: Fix success-path group lookup ownership in `vdev_get_group()` by returning the allocated buffer via `*grp_buf`.
- **fs/fs.c**: Harden fd handle packing/unpacking by replacing fixed 4-byte copies with `sizeof(fd)`.
- **fs/fs.c**: Fix `readdir` ACL filtering to evaluate each real child entry path/name (`dirents[i]->name`) and log the filtered entry correctly.
- **fs/README.md**: Add practical vdevfs documentation with ACL usage example and explicit `eventfs` vs `vdevfs` scope notes.
- **vdevd/vdev.h**, **vdevd/vdev.c**: Add `struct vdev_globals` inside `vdev_state` and centralize profile/state naming (`sysfs`, `config_dir`, `initrd`, `early`, `early-coldplug`, `long-running`) with defaults.
- **vdevd/vdev.c**: Add optional `vdevd.globals.json` loader (searched beside active `config_path`; packaged under `/etc/vdev`). Invalid/missing JSON falls back to defaults with warning.
- **vdevd/os/linux.c**, **vdevd/main.c**: Replace key hardcoded config-name checks with globals-backed values and helper functions.
- **vdevd/vdev.c**, **vdevd/os/linux.c**: Wire JSON-configurable subsystem queues into coldplug registration for phase profiles (`vdevd.0`, `vdevd.1`, `vdevd.initrd`) instead of local hardcoded arrays.
- **example/vdevd.globals.json**, **how-to-test.md**, **example/actions/README.md**: Ship JSON examples, `*.json` configs, and document editing/verification flow for globals and subsystem queues.

### vdev (1.3.95) — 28 Apr 2026

- **vdevd/helpers/LINUX/vdev_root_sys_block.c**, **vdevd/helpers/LINUX/vdev_print_input_devices.c**: Stop assuming fixed `/sys`; accept sysfs mountpoint via CLI (`vdev_root_sys_block [SYSFS_MOUNTPOINT]`, `vdev_print_input_devices [SYSFS_MOUNTPOINT] [SETTLE_MS]`) with backward-compatible argument parsing.
- **example/sysv-initscript.sh**: Parse `sysfs` from `vdevd.globals.json` via `jq` and pass it to helper binaries.
- **vdevd/helpers/LINUX/udisks2.sh**, **example/actions/udisks2.act**: Remove `VAR_UDISKS_SYSFS` from action config and pass sysfs explicitly from shell to `vdev_root_sys_block`.
- **example/actions/README.md**: Drop `VAR_UDISKS_SYSFS` documentation and add `VDEV_GLOBALS_JSON` to the environment variable reference.
- **vdevd/os/linux.c**, **vdevd/os/linux_sysfs.inc**, **vdevd/os/linux_events.inc**, **vdevd/os/linux_bootstrap.inc**: Split the Linux backend by function (sysfs/coldplug discovery, event loop handling, bootstrap init/shutdown) to reduce monolithic file size while preserving behavior.
- **vdevd/os/linux_sysfs.inc**, **vdevd/os/linux_events.inc**, **vdevd/os/linux_bootstrap.inc**: Add editor modeline header (`-*- mode: c; -*-`) so `.inc` modules are syntax-highlighted as C code consistently.
- **vdevd/helpers/LINUX/keyboard-default.sh**, **example/actions/kbd-default.act**: Add keyboard-default action/helper to apply `/etc/default/keyboard` on `event=add` + `path=^kbd$` (udev `KERNEL=="kbd"` equivalent expressed in vdev via `VDEV_PATH` regex matching).
- **example/actions/README.md**: Expand and polish action documentation: field semantics, `path=` ERE vs `OS_DEVPATH`, explicit `KERNEL ↔ path` mapping, queue-tracking behavior and negative flags, and keyboard-default section.
- **example/actions/udisks2.act**, **example/actions/zzz-udev-compat.act**: Set `if_exists=run` for metadata/compat refresh actions; README now cites `sound-alsa-control.act` as existing `if_exists` usage and documents the now-adopted policy.
- **example/actions**: Rename `000-udisks2.act` → `udisks2.act` (still sorts before `zzz-udev-compat.act`); comments and `VAR_`* lines on `udisks2.act`, `seat.act`, `uaccess.act`.
- **vdevd/helpers/LINUX/udisks2.sh**, **subr-event.sh**: Optional `VAR_UDISKS_PROPS_BASENAME` (default `udisks-props`); write `$VDEV_METADATA/.vdev-udisks-props-basename` so `event_generate_text()` uses the same basename without duplicating it in shell.
- **example/actions/README.md**: Document `OS_`* vs `VAR_`* (including empty `OS_` semantics), `path=` ERE vs `OS_DEVPATH`, lexicographic action order vs logs, `udisks2` relative to `zzz / zzzz`, `zzzz-os-queue-tracking.act` and negative `QUEUE_TRACKING_FLAG`; `See also` `os-queue-tracking.sh`.

### vdev (1.3.94) — 27 Apr 2026

- **third-party/uni-json/examples**: Add comprehensive JSON manipulation examples:
  - **simple/** directory with basic JSON parsing example (`simple.c`, `c_bindings.c`, `Makefile`)
  - **nested/** directory with advanced nested JSON manipulation (`nested_example.c`, `nested_bindings.c`, `Makefile`)
  - Examples demonstrate parsing, querying, creation, and modification of JSON structures
  - Includes proper memory management, error handling, and pretty-printing capabilities
  - Documentation with usage examples and integration guidelines for vdev
- **vdevd**: `-j / --kill-peers-exit` — same `vdev_kill_peer_processes("vdevd")` as `-k`, then exit before preseed/daemon (for SysV `stop`).
-  SysV script **example/sysv-initscript.sh**: vdevd_stop() runs `vdevd -j -c "$VDEV_CONFIG"` via `vdevd_kill_peers_for_stop` before `vdevd_find_running_pid / SIGTERM`, mirroring peer cleanup on `start`.
- **third-party/dmidecode-builtin**: Vendor dmidecode `util.c`, `util.h`, `types.h`, `config.h` under `vendor/` so `dmidecode-chassis-type-builtin` builds without a separate `dmidecode-3.6` checkout.
- **Udisks / block:** Move `UDISKS_`* and `VDEV_FS_`* emission out of `subr-event.sh` into `lib/vdev/udisks2.sh`, run via `000-udisks2.act` (`type=block`, `event=any`) so it executes before `zzz-udev-compat`. `event_generate_text` reads `$VDEV_METADATA/udisks-props` (or `UDISKS_IGNORE=1` if absent).
- **example/actions**: Add `000-udisks2.act`.

### vdev (1.3.93) — 26 Apr 2026

- **third-party/dmidecode-builtin**: Minimal `dmidecode-chassis-type-builtin` (sysfs SMBIOS only, `util.c` from upstream `dmidecode`); built with `vdevd` helpers and installed under `lib/vdev`; `debian/copyright` documents GPL-2+.
- **libvde/dmi_chassis_builtin.h**, **vdev_dmi_chassis_type_is_tower_or_desktop()** — try `VDEV_DMI_CHASSIS_BUILTIN` / default builtin path, then `/usr/sbin/dmidecode` pipeline.
- **vdevd/os/linux.c**, **vdevd/helpers/LINUX/vdev_modprobe.c**: Use `vdev_dmi_chassis_type_is_tower_or_desktop()` (remove duplicated `popen` chassis logic).
- **libvdev/misc.c / misc.h**: Add `vdev_fanotify_path_is_login_or_xorg()` (basename + dirname checks for login / Xorg executables) for fanotify “skip” logic.
- **libvdev/config.c / config.h**: Remove `--sync` argument, no longer required

### vdev (1.3.92) — 25 Apr 2026

- **vdevd/os/linux.c** and **vdevd/helpers/LINUX/vdev_modprobe.c**: Call the helper so login-session and modprobe fanotify paths stay aligned; comment in `vdev_modprobe.c` points to `linux.c`.
- **vdevd/main.c**: Comments clarifying `vdev_daemonize` (pipe parent) vs `vdev_detach_session` (`coldplug_only`).
- SysV **example/sysv-initscript.sh**: Invoke `vdevd` with `-k` on `start` and on the subshell `exec` to `vdevd.conf`, so `vdev_kill_peer_processes` runs before the new instance binds.
- **Helpers:** Remove `vdev_killall`; `vdevd -k / vdev_kill_peer_processes` covers prior-instance teardown.
- **libvdev/misc.c / misc.h**: Remove unused `get_user_sessions()` and `utmp` include.
- **libvdev/misc**: Rename `send_to_background` → `vdev_detach_session` (double-fork detach); after `setsid`, `signal(SIGCHLD, SIG_IGN)`; close inherited file descriptors (bounded by `sysconf(_SC_OPEN_MAX)`), then `dup2` stdin/stdout/`stderr` to `/dev/null`.
- Sysv **example/sysv-initscript.sh**: `vdevd_start` chooses `VDEV_START_CONFIG`: `vdevd.1.conf` when `vdevd-0-coldplug.ready` exists and `vdevd-1-coldplug.ready` does not (first `start`, phase 1 not finished); `vdevd.conf` when stamp `1` exists (`restart` without repeating `vdevd.1` coldplug) or when `/dev/block` and no stamp `0`; `eval $(source_ini_file …)` again if `VDEV_START_CONFIG` differs from global `VDEV_CONFIG`. Global `VDEV_CONFIG` still tracks stamp `0` for `stop`/`status` hints; `vdevd_find_running_pid` factors the multi-pidfile scan for `stop` and `status`.
- Sysv **example/sysv-initscript.sh**: `VDEV_CONFIG` selection prefers `$VDEV_COLDPLUG_STAMP_DIR/vdevd-0-coldplug.ready` (phased `vdevd.0` finished) over `/dev/block` alone, with `/dev/block` still selecting `vdevd.conf` when there is no stamp (non-phased installs). `export VDEV_COLDPLUG_STAMP_DIR` runs before this check.

### vdev (1.3.91) — 25 Apr 2026

- Sysv **example/sysv-initscript.sh**: `vdevd_stop` walks `$vdev_config_pidfile`, then `/run/vdev/vdevd_1.pid` and `/run/vdev/vdevd.pid`, and only signals a PID whose `/proc/…/comm` is `vdevd`, so halt/reboot still stops `vdevd` when phased boot is still in `vdevd.2` but `/dev/block` already made the script load `vdevd.conf` (wrong pidfile alone). LSB `Default-Stop: 0 6` and `Required-Stop: $local_fs`.
- Sysv **example/sysv-vdev-x11-sync.sh**: `Required-Start: $local_fs` only; `Should-Start: vdev $network` so `insserv` / `update-rc.d` do not treat `vdev` as a hard prerequisite that must already be enabled (avoids common `FATAL` during `dpkg configure`). The `start` action still blocks on `x11-sync.ready`.
- **vdevd/vdev.c**: After `vdev_reload`, if the new config omits `mountpoint`, inherit it from the previous config; refresh `vdev->mountpoint` from the active config; `vdev_error_thread_start()` uses `config->mountpoint` with fallback to `vdev->mountpoint` so `mkfifo` for `metadata/.../err.pipe` does not see a NULL path on the `SIGHUP` transition to `vdevd.2.conf`.
- **lib/vdev/daemonlet**: In `daemonlet_default_environ()`, `VDEV_DAEMONLET=""` alongside the other cleared variables.
- **vdevd/helpers/LINUX/vdev_print_input_devices.c**: Optional `SETTLE_MS` command-line argument for `wait_for_input_settle("/dev/input", …)`; `usage()` and `-h / --help`. Default quiet period reduced from `1000` ms to `250` ms (init scripts unchanged). Maximum total wait for `/dev/input` settle remains `10` s.
- Sysv **example/sysv-initscript.sh**: In `vdevd_start`, after preparing log and pid directories, wait for `$VDEV_COLDPLUG_STAMP_DIR/vdevd-0-coldplug.ready` (bounded poll like the `vdevd.1` subshell stamp wait; `VDEV_OS_QUEUE_TRACKING_FLAG=1` / `os-queue-tracking.sh`) and only then emit `log_daemon_msg "Starting the system device event dispatcher"` before starting `vdevd`.
- **vdevd/device.c**: If `vdev_action_create_path` fails or there is no `path/renamed_path` while `QUEUE_TRACKING_FLAG` is `positive`, negate that flag (discard marker), skip `mkdir`/`mknod`/metadata`, and still run helpers. No `UNKNOWN` path rename for this path.
- **vdevd/action.c / action.h**: New `queue_tracking_handler` flag on actions (INI `queue_tracking_handler=`); `vdev_action_match` returns no match for requests with `negative` `QUEUE_TRACKING_FLAG` unless the action opts in (default `false` for all existing rules).
- **example/actions/zzzz-os-queue-tracking.act**: set `queue_tracking_handler=1` so `os-queue-tracking.sh` still runs on `-1`/`-2`/`-3`.
- **vdevd/helpers/LINUX/os-queue-tracking.sh**: `case` arms accept `1|-1`, `2|-2`, `3|-3`.
- **vdevd/vdev.c / main.c**: `vdev_reload(vdev, default_config_path)` — fast path loads phase-2 config without re-running `getopt` when the default path is passed (e.g. `/etc/vdev/vdevd.2.conf` on `SIGHUP`).

### vdev (1.3.90) — 24 Apr 2026

- **vdevd/os/linux.c**: Remove the static `reloaded` flag; `vdev_linux_is_reloaded()` detects the phase-2 profile from the current `config_path` basename (`vdevd.2.conf`). Replace `responsive_to_netlink_events` with `vdev_linux_stop_netlink()` (close netlink and clear its `pollfd`). `shutdown_fanotify()` now clears the fanotify `pollfd` after `close` to avoid a second `close` in shutdown; the shutdown loop closes the netlink slot as well. `vdev_linux_context_init()`: provisional `FIXME` block — when the reloaded profile is active, set `os_ctx->coldplug_only` so phase 2 still behaves as coldplug-only (under review).
- **LSB headers:** **vdev** **Provides: vdev udev**; **vdev-x11-sync.sh** **Required-Start: vdev $local_fs** (replacing `udev`) so `insserv` orders after `vdev` without deleting `eudev`’s file.
- SysV **example/sysv-initscript.sh**: `vdevd_stop` exits cleanly when the pidfile is already gone; `status` avoids reading a missing file and uses LSB-like exit codes (`0` running, `3` not running, `1` stale pidfile or misconfiguration).
- SysV **example/sysv-initscript.sh**: `subshell()` Remove `lslocks` idle fallback; the subshell only waits (bounded) for `vdevd-1-coldplug.ready`.
- **example:** Install script `/etc/init.d/vdev-x11-sync.sh`; `example/conf.mk` and `example/Makefile`.

### vdev (1.3.89) — 23 Apr 2026

- **vdevd (vdev.c / vdev.h)**: Remove `vdev_start()` pidfile `F_WRLCK` for `vdevd.0.conf` / `vdevd.1.conf`, the `lock_fd` field, and the matching unlock in `vdev_signal_coldplug_finished()`.
- **vdev_modprobe**: Remove `/run/vdev_modprobe.pid` write and `unlink`; the former pidfile path was not an exclusive lock after `fcntl` locking was dropped, and ordering no longer depends on it.
- **Linux / helpers:** Synthetic uevent field renamed to `QUEUE_TRACKING_FLAG` (was `TRACKING_FLAG`); environment variable `VDEV_OS_QUEUE_TRACKING_FLAG` (was `VDEV_OS_TRACKING_FLAG`). `daemonlet` default environ and `os-queue-tracking.sh` updated.
- **os-queue-tracking.sh** + **zzzz-os-queue-tracking.act** (`daemonlet=false`, `event=any`): single place for `VDEV_OS_QUEUE_TRACKING_FLAG` `1` / `2` / `3` (uevent key `QUEUE_TRACKING_FLAG`; coldplug stamps under `/run/vdev` and `SIGTERM` to `$PPID` for phase 2 end). Installed for `actions.0`, `actions.1`, and default `actions`. `modprobe.sh` and `udev-compat.sh` no longer contain tracking-flag side effects (supersedes `-21` `coldplug-stamp`).
- **coldplug-stamp.sh** + **zzz-coldplug-stamp.act**: Write `vdevd-1-coldplug.ready` on `TRACKING_FLAG=2` for `any` subsystem so `zzz-udev-compat.act` (`OS_SUBSYSTEM=input`) does not prevent the stamp when the last sysfs-queue uevent is not input. `udev-compat.sh` no longer duplicates that stamp — `superseded in -22` by `os-queue-tracking.sh`.
- **Coldplug stamps:** **modprobe.sh** / **udev-compat.sh** write `vdevd-0-coldplug.ready` and `vdevd-1-coldplug.ready` under `/run/vdev` (override with `VDEV_COLDPLUG_STAMP_DIR`, same `.ready` pattern as `x11-sync.ready`), avoiding early `mkdir` under `/dev/metadata` — `-21` moves the phase-1 end stamp to `coldplug-stamp.sh` (see above).
- **SysV init:** `subshell()` wait, stale `rm`, and `export VDEV_COLDPLUG_STAMP_DIR` aligned with helpers; `vdev-modprobe` removes `vdevd-0-coldplug.ready` before start.
- **modprobe.sh / udev-compat.sh**: Use `[ "${VDEV_DAEMONLET:-0}" -eq 0 ]` so dash does not error on an empty variable.

### vdev (1.3.88) — 23 Apr 2026

- Coldplug `TRACKING_FLAG` **os/linux.c**: Distinct values per stage: last sysfs subsystem-queue uevent uses `1` for `vdevd.0.conf` and `2` for `vdevd.1.conf` (`vdev_linux_sysfs_register_devices_subsystem_queue(..., tracking_flag_last)`); last plain-queue uevent for `vdevd.2.conf` uses `3` (replacing the former `2`-only marker).
- **modprobe.sh**: When `VDEV_OS_TRACKING_FLAG=1`, touch a coldplug stamp after `modprobe` (early fingerprint for `vdevd.0`; superseded in `-20` by `/run/vdev/vdevd-0-coldplug.ready`).
- **udev-compat.sh**: `TRACKING_FLAG=2` → coldplug stamp for `vdevd.1`; `TRACKING_FLAG=3` → `SIGTERM` to `$PPID` (replaces the old `2`-only `vdevd.2` path).
- **vdev_modprobe.c**: Remove the `pidfile` `fcntl` write lock and the fixed `sleep(10)` before the netlink phase (coordination is intended to use stamps / init ordering instead).
- SysV init **example/sysv-initscript.sh**: The `vdevd.1` subshell waits for the coldplug stamp (path revised in `-20`), with timeout (`lslocks` fallback removed in `-26`). `vdevd_start` removes a stale stamp when starting `vdevd.1.conf`.
- **vdev-modprobe` init (`example/sysv-modprobe.sh**: Default `VDEV_MOUNTPOINT`, `rm -f` stale coldplug stamp before `start`, pass `"$VDEV_MOUNTPOINT"` to `vdevd`.

### vdev (1.3.87) — 23 Apr 2026

- **vdev_start()` (`vdevd/vdev.c**: Before `vdev_os_context_init`, set `vdev->coldplug_only = vdev->config->coldplug_only` on every backend start. After `vdev_reload` (e.g. `SIGHUP` moving from `vdevd.1.conf` to `vdevd.2.conf`), the OS context therefore picks up `coldplug_only` from the current INI instead of the value cached at `vdev_init`.

### vdev (1.3.86) — 23 Apr 2026

- **Linux (`os/linux.c**: Remove the hack that forced `os_ctx->coldplug_only = true` when the config file was `vdevd.2.conf`. Still set `reloaded = true` for that basename so `vdev_os_next_device` does not stop when the initial device queue is empty in phase 2 while `coldplug_only` stays true in config.

### vdev (1.3.85) — 23 Apr 2026

- **Linux:** Refactor `vdevd.0` / `vdevd.1` coldplug into `vdev_linux_sysfs_register_devices_subsystem_queue()` with `sysfs_reg_tower_skip_v0` / `_v1`; the last queued uevent keeps `TRACKING_FLAG` for daemonlets (same idea as `vdevd.2.conf`).

### vdev (1.3.84) — 22 Apr 2026

- **Linux:** In `vdev_linux_sysfs_register_devices`, free each uevent path before `sglib_cstr_vector_set(..., NULL, j)` — `sglib_vector_set` does not release the old `char`* (same contract as `vdev_cstr_vector_free_all`).

### vdev (1.3.83) — 22 Apr 2026

- **Build:** Default `make` target is `build` (libvdev, vdevd, fs, example) without `hwdb.squashfs`. Full tree uses `make all` (copy `hwdb/hwdb.squashfs` if present, else `hwdb` `all-full`). `hwdb/Makefile` gains `all-full` and optional install when the squashfs is missing.

### vdev (1.3.82) — 21 Apr 2026

- **example/Makefile**: Build SysV init scripts into `$(BUILD)/etc/init.d` from `sysv-initscript.sh`, `sysv-modprobe.sh`, and `sysv-vdev-x11-sync.sh` (aligned with `example/conf.mk`); extend `clean`; fix initramfs prerequisite and remove stale `VDEV_INSTALL_SCRIPT` rules.

### vdev (1.3.81) — 21 Apr 2026

- **Linux signals (`os/linux.c**: Replace the `sig_handler` + static `linux_signal` pattern with `blocked signals` and a non-blocking `signalfd`. `vdev_linux_signals_block_for_signalfd()` runs at the start of `vdev_start()` (before any `pthread_create`) so worker threads inherit the mask. After `poll`, pending events are read from `struct signalfd_siginfo` (including the initrd timeout / emergency `SIGTERM` path for `vdevd.initrd.conf`).
- **Forked children (`libvdev/daemonlet.c`, `vdevd/action.c**: Clear the signal mask with `sigprocmask(SIG_SETMASK, …)` in the child before `exec`, so `daemonlets` and async helper processes do not inherit `vdevd`’s` blocked signals (which would prevent `vdev_daemonlet_stop()`’s `SIGINT` from being delivered and could stall service shutdown).
- SysV init **example/sysv-initscript.sh**: `vdevd_stop` sends `SIGTERM`, waits up to ~15 seconds for the pidfile PID to disappear, then `SIGKILL` if needed; `log_end_msg` no longer treats `kill(1)` success as proof the daemon has exited.

### vdev (1.3.80) — 20 Apr 2026

- **DRM by-path:** New `dri.sh` helper used by `dri.act`. On `add`, it calls `stat_path` (udev `path_id` equivalent) and creates `/dev/dri/by-path/$VDEV_PERSISTENT_PATH-{card,control,render}` symlinks for `dri/card*`, `dri/controlD*`, and `dri/renderD*`, matching eudev `60-drm.rules`. Device ownership and mode are still applied by invoking `permissions.sh` afterwards (same as the previous `helper=permissions.sh` setup).

### vdev (1.3.79) — 19 Apr 2026

- **Seat actions:** Remove the misleading `nouveau.act / nouveau.sh` name (the helper applied to all DRM KMS nodes, not only the Nouveau driver) and fold that behaviour together with `input-seat.act / input-seat.sh` into a single `seat.act` and unified `seat.sh`. The action matches `dri/card*`, `dri/renderD*`, and `input/event*`; tags and group permissions (video, render, input) are handled in one place, in line with what `elogind` / `logind` expect from udev-style seat metadata.
- **Udev tag `seat`**: Emit metadata tag `seat` instead of `seat0`. The conventional udev tag for seat membership is `seat`; `seat0` is normally the seat *name* (e.g. `ID_SEAT`), not a tag label. This aligns vdev metadata with rules such as systemd `71-seat.rules`.

### vdev (1.3.78) — 18 Apr 2026

- **subr-event.sh:** for `SUBSYSTEM=block`, run `vdev_block_info` only if `$VDEV_MOUNTPOINT/$VDEV_OS_DEVNAME` exists; otherwise emit `UDISKS_IGNORE=1`. Avoids blkid on a missing `/dev/…` node (common on `remove`) and the duplicate stderr “Failed to open” lines from the size and label probes.
- **vdev_block_info:** log open failures with a full line (`strerror`, newline); use `printf("%s", …)` for size and label output.

### vdev (1.3.77) — 16 Apr 2026

- **event-put:** remove `serial_trim / resync_head_tail` — unlinking or recreating eventfs `head`/`tail` from userspace emptied queues and broke Xorg listeners.

---

## Historical Note
Versions prior to **v1.3.77** are not detailed in this document.
