Fixes for home-manager to work, now multi-user daemon-less works
end-to-end, although not optimal
This commit is contained in:
parent
e287082dba
commit
bfead1719d
5 changed files with 312 additions and 372 deletions
|
|
@ -94,10 +94,10 @@ let
|
|||
export EXT2FS_NO_MTAB_OK=yes
|
||||
fsck.ext4 -n -f rootfs.img
|
||||
|
||||
# Shrink to actual content size, then add 2 GiB headroom for in-VM builds
|
||||
# Shrink to actual content size, then add 4 GiB headroom for in-VM builds
|
||||
resize2fs -M rootfs.img
|
||||
new_size=$(dumpe2fs -h rootfs.img 2>/dev/null | awk -F: \
|
||||
'/Block count/{count=$2} /Block size/{size=$2} END{print int((count*size + 2 * 2^30) / size)}')
|
||||
'/Block count/{count=$2} /Block size/{size=$2} END{print int((count*size + 4 * 2^30) / size)}')
|
||||
resize2fs rootfs.img "$new_size"
|
||||
echo "Final ext4 size: $(( $(stat -c %s rootfs.img) / 1024 / 1024 )) MiB"
|
||||
|
||||
|
|
|
|||
580
reference.md
580
reference.md
|
|
@ -4,27 +4,129 @@
|
|||
|
||||
A minimal, non-systemd Linux system with Nix as the operating system layer.
|
||||
dinit for PID 1 and process supervision. NixOS module system for declarative
|
||||
configuration. Bubblewrap for service sandboxing. No Nix daemon by default.
|
||||
|
||||
The key insight: you don't need NixOS to get most of its benefits — just Nix +
|
||||
the NixOS module evaluator + cherry-picked modules + a translation shim for
|
||||
services.
|
||||
configuration. Bubblewrap for service sandboxing. No Nix daemon.
|
||||
|
||||
Two core principles drive the architecture:
|
||||
1. **dinit over runit** — proper dependency DAG, parallel boot, native service
|
||||
types that map cleanly to systemd, readiness notification, cgroup placement.
|
||||
2. **Daemon-less Nix** — the system store is root-owned (single-user Nix), user
|
||||
stores are per-user (daemon-less Home Manager). No nix-daemon by default.
|
||||
stores are per-user overlay stores. No nix-daemon.
|
||||
|
||||
---
|
||||
|
||||
## Flake Architecture
|
||||
|
||||
Two independent flakes. The distro flake is build tooling — it never leaks
|
||||
into the end machine. The machine flake lives on the device and drives both
|
||||
system rebuilds and user configuration.
|
||||
|
||||
```
|
||||
DISTRO FLAKE (git.axiomania.org/lebowski/MiNix)
|
||||
Build tooling only — produces images, exports lib + modules.
|
||||
Never baked into end machines.
|
||||
|
||||
inputs:
|
||||
nixpkgs-stable github:NixOS/nixpkgs/nixos-25.11
|
||||
nixpkgs-unstable github:NixOS/nixpkgs/nixos-unstable
|
||||
home-manager github:nix-community/home-manager/release-25.11
|
||||
|
||||
outputs:
|
||||
lib.minixSystem eval function for machine flakes
|
||||
homeModules.default hm-dinit.nix (dinit user service module)
|
||||
packages.*.vm disk image (dev only)
|
||||
devShells.* qemu, debug tools
|
||||
|
||||
MACHINE FLAKE (/etc/minix/ on end device)
|
||||
Per-machine config. Mutable — installed on first boot, user edits persist.
|
||||
References distro via git+https:// (resolved by narHash, no path: fetcher).
|
||||
|
||||
inputs:
|
||||
minix git+https://git.axiomania.org/lebowski/MiNix.git
|
||||
nixpkgs-stable follows minix/nixpkgs-stable
|
||||
nixpkgs-unstable follows minix/nixpkgs-unstable
|
||||
|
||||
outputs:
|
||||
packages.*.system systemProfile (minix.lib.minixSystem + ./configuration.nix)
|
||||
|
||||
USER HM FLAKE (~/.config/home-manager/ per user)
|
||||
Fully independent from machine flake. Auto-scaffolded on first boot.
|
||||
User owns and edits these files.
|
||||
|
||||
inputs:
|
||||
minix git+https://git.axiomania.org/lebowski/MiNix.git
|
||||
nixpkgs follows minix/nixpkgs-stable
|
||||
home-manager follows minix/home-manager
|
||||
|
||||
outputs:
|
||||
homeConfigurations.<user> HM config (./home.nix)
|
||||
```
|
||||
|
||||
### Input flow (follows chain)
|
||||
|
||||
```
|
||||
git+https://git.axiomania.org/lebowski/MiNix.git
|
||||
|
|
||||
distro flake
|
||||
/ | \
|
||||
nixpkgs-stable nixpkgs-unstable home-manager
|
||||
| | |
|
||||
"follows" "follows" "follows"
|
||||
| | |
|
||||
machine flake (/etc/minix/) user flake (~/.config/home-manager/)
|
||||
|
||||
One fetch (distro flake) pins everything. Machine and user flakes
|
||||
have zero independent inputs — all shared via follows.
|
||||
```
|
||||
|
||||
### Why git+https:// (not path:)
|
||||
|
||||
The `path:` flake fetcher triggers `builtins.path { filter; }` which copies
|
||||
store paths. In a local-overlay-store, this creates a SYMLINK in the upper
|
||||
layer instead of a real directory. Nix then rejects it: "path is a symlink".
|
||||
|
||||
`git+https://` inputs are locked by narHash. The overlay store resolves
|
||||
narHashes by reading the lower store's DB — if the system build already
|
||||
fetched the input, it's found without any copy. No symlink, no bug.
|
||||
|
||||
### On-device layout
|
||||
|
||||
```
|
||||
/etc/minix/ mutable (first-boot copy, edits persist)
|
||||
flake.nix machine flake (git+https://...MiNix)
|
||||
flake.lock locked pins
|
||||
configuration.nix system config
|
||||
hardware-configuration.nix hardware-specific
|
||||
|
||||
~/.config/home-manager/ per-user, auto-scaffolded on first boot
|
||||
flake.nix user flake (git+https://...MiNix)
|
||||
flake.lock locked pins
|
||||
home.nix HM config
|
||||
```
|
||||
|
||||
### Who evaluates what
|
||||
|
||||
```
|
||||
ROOT (minix-rebuild build):
|
||||
nix build /etc/minix#packages.<arch>.system
|
||||
-> fetches minix from Forgejo (by narHash)
|
||||
-> minix.lib.minixSystem { modules = [ ./configuration.nix ] }
|
||||
-> systemProfile -> nix-env --set -> reboot
|
||||
|
||||
USER (home-manager switch):
|
||||
home-manager switch --flake ~/.config/home-manager
|
||||
-> fetches minix from Forgejo (narHash hit — already in lower store)
|
||||
-> homeConfigurations.<user> -> builds in overlay store -> activates
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
Layer 2: User Environment (Home Manager, per-user Nix store)
|
||||
Layer 2: User Environment (Home Manager, per-user overlay store)
|
||||
Per-user, declarative. Owns $HOME only.
|
||||
Packages, dotfiles, user dinit services.
|
||||
Own Nix store (~/.local/share/nix/store) — no daemon needed.
|
||||
Overlay store: ~/.local/share/nix/ upper on /nix/store lower.
|
||||
Updated: home-manager switch (live, no reboot)
|
||||
|
||||
Layer 1: System Profile (root-owned Nix store, single-user Nix)
|
||||
|
|
@ -55,34 +157,41 @@ generated as Nix derivations and live inside the system profile. The system
|
|||
profile is self-contained — switch profiles by pointing
|
||||
`/nix/var/nix/profiles/system` at a new store path and rebooting.
|
||||
|
||||
### Daemon-less Nix stores
|
||||
### Per-user overlay stores
|
||||
|
||||
```
|
||||
/nix/store (system) — owned by root, single-user Nix mode
|
||||
minix-rebuild runs nix build directly as root
|
||||
read-only bind mount at runtime (minix.hardenStore)
|
||||
/nix/store (system) — root-owned, single-user Nix mode
|
||||
minix-rebuild runs nix build as root
|
||||
read-only bind mount at runtime (minix.hardenStore)
|
||||
= overlay "lower" layer
|
||||
|
||||
~/.local/share/nix/ (user) — owned by each user, daemon-less
|
||||
Home Manager operates against this store
|
||||
binary cache for substitutes (no local rebuilds needed)
|
||||
user dinit services reference paths in this store
|
||||
~/.local/share/nix/ (user) — per-user, daemon-less
|
||||
upper/ overlayfs upper layer (new packages go here)
|
||||
work/ overlayfs work directory
|
||||
merged/nix/store/ overlayfs mount point
|
||||
var/nix/ overlay store state (db, profiles, gcroots)
|
||||
```
|
||||
|
||||
No nix-daemon service. No nix-daemon.socket. No nixbld build users. The daemon
|
||||
is available as an opt-in for multi-user shared-store setups, not a default.
|
||||
Mount namespace setup (user-init at boot):
|
||||
1. `unshare --mount` creates a new mount namespace
|
||||
2. Bind-mount ns handle to `/run/user/$UID/ns/mnt`
|
||||
3. `nsenter` sets up overlayfs: lower=/nix/store, upper=~/.local/share/nix/upper
|
||||
4. Bind-mount merged store over /nix/store within the namespace
|
||||
5. `pam_minix_ns.so` enters the namespace at login via `setns()`
|
||||
|
||||
The store boundary and dinit instance boundary align: system dinit (PID 1)
|
||||
launches system services from `/nix/store`; user dinit instances (`dinit --user`)
|
||||
launch user services from the user's store. No cross-store references.
|
||||
Store DB permissions: `/nix/var/nix/db/` group-writable by `users` so overlay
|
||||
store can read the lower store's sqlite DB (narHash lookups).
|
||||
|
||||
No nix-daemon. No nix-daemon.socket. No nixbld build users.
|
||||
|
||||
### dinit service supervision
|
||||
|
||||
```
|
||||
PID 1: dinit --system
|
||||
├── early-* services (scripted: pseudofs, eudev, modules, hostname, etc.)
|
||||
├── system services (translated from systemd.services.*)
|
||||
└── user dinit instances (spawned at login)
|
||||
└── user services (from Home Manager / user store)
|
||||
+-- early-* services (scripted: pseudofs, eudev, modules, hostname, etc.)
|
||||
+-- system services (translated from systemd.services.*)
|
||||
+-- user dinit instances (spawned by turnstile at login)
|
||||
+-- user services (from Home Manager / user store)
|
||||
```
|
||||
|
||||
dinit provides dependency-ordered parallel startup, readiness notification,
|
||||
|
|
@ -146,46 +255,42 @@ NixOS initrd -> switch_root -> $PROFILE/init (minix-init)
|
|||
|
||||
### 3-layer boot DAG
|
||||
|
||||
dinit starts the `boot` service by default. The boot DAG is 3 layers deep:
|
||||
|
||||
```
|
||||
boot (internal)
|
||||
├── depends-on: system
|
||||
└── waits-for: serial-getty@ttyS0, autovt@tty1 (login last)
|
||||
+-- depends-on: system
|
||||
+-- waits-for: serial-getty@ttyS0, autovt@tty1 (login last)
|
||||
|
||||
system (internal)
|
||||
├── depends-on: early
|
||||
└── waits-for: sshd, dhcpcd, firewall, ... (all auto-start services)
|
||||
+-- depends-on: early
|
||||
+-- waits-for: sshd, dhcpcd, firewall, ... (all auto-start services)
|
||||
|
||||
early (internal)
|
||||
└── depends-on: early-sysinit, early-hostname, early-loopback
|
||||
+-- depends-on: early-sysinit, early-hostname, early-loopback
|
||||
|
||||
early-sysinit (scripted)
|
||||
└── depends-on: early-etc, early-eudev, early-modules
|
||||
├── tmpfiles --create --remove
|
||||
├── sysusers (create/merge users, groups, passwords)
|
||||
├── machine-id
|
||||
├── sysctl
|
||||
├── fstab mount
|
||||
├── seedrng (entropy credit)
|
||||
├── nix store registration
|
||||
├── store hardening (optional)
|
||||
└── activation scripts
|
||||
+-- depends-on: early-etc, early-eudev, early-modules
|
||||
tmpfiles --create --remove
|
||||
sysusers (create/merge users, groups, passwords)
|
||||
machine-id, sysctl, fstab mount
|
||||
seedrng (entropy credit)
|
||||
nix store registration
|
||||
store hardening (optional)
|
||||
activation scripts
|
||||
|
||||
early-etc (scripted) — populate /etc from profile
|
||||
└── depends-on: early-pseudofs
|
||||
+-- depends-on: early-pseudofs
|
||||
|
||||
early-eudev (scripted) — udevd + coldplug + settle
|
||||
└── depends-on: early-pseudofs
|
||||
+-- depends-on: early-pseudofs
|
||||
|
||||
early-modules (scripted) — link kernel modules, load modules-load.d
|
||||
└── depends-on: early-pseudofs, early-etc
|
||||
+-- depends-on: early-pseudofs, early-etc
|
||||
|
||||
early-hostname (scripted)
|
||||
└── depends-on: early-etc
|
||||
+-- depends-on: early-etc
|
||||
|
||||
early-loopback (scripted) — bring up lo
|
||||
└── depends-on: early-pseudofs
|
||||
+-- depends-on: early-pseudofs
|
||||
|
||||
early-pseudofs (scripted) — mount tmp, devpts, shm, cgroup2, /run/wrappers
|
||||
```
|
||||
|
|
@ -202,6 +307,7 @@ dinit instance spawning:
|
|||
Login flow:
|
||||
user logs in via getty/sshd
|
||||
-> PAM calls pam_turnstile.so (session rule)
|
||||
-> pam_minix_ns.so enters user's mount namespace (overlay store)
|
||||
-> turnstiled spawns dinit --user for that UID
|
||||
-> XDG_RUNTIME_DIR created at /run/user/$UID
|
||||
-> user dinit reads ~/.config/dinit.d/ + /etc/dinit.d/user/
|
||||
|
|
@ -211,21 +317,8 @@ Logout flow:
|
|||
last session for UID closes
|
||||
-> turnstiled stops user dinit instance
|
||||
-> XDG_RUNTIME_DIR cleaned up
|
||||
(linger=maybe checks /var/lib/turnstiled/linger/<username>)
|
||||
```
|
||||
|
||||
Boot placement: `turnstiled` is a process service with `dependsMs = [ "early" ]`,
|
||||
auto-starts via system milestone, ready before gettys accept login.
|
||||
|
||||
Configuration:
|
||||
- `/etc/turnstile/turnstiled.conf` — backend selection, rundir, linger policy
|
||||
- `/etc/turnstile/backend/dinit.conf` — user dinit service directories
|
||||
- `/etc/dinit.d/user/` — system-provided user services (D-Bus, PipeWire, etc.)
|
||||
- `/etc/dinit.d/user/boot.d/` — system-provided user boot services
|
||||
|
||||
PAM integration: `pam_turnstile.so` added to login, sshd, su, sudo session
|
||||
rules (order 11900). Separate `turnstiled` PAM service for backend spawning.
|
||||
|
||||
### /etc population (early-etc)
|
||||
|
||||
- Symlinks for immutable files (store paths)
|
||||
|
|
@ -234,15 +327,6 @@ rules (order 11900). Separate `turnstiled` PAM service for backend spawning.
|
|||
- Stale symlinks from previous profiles cleaned up
|
||||
- passwd/shadow/group/gshadow NOT in /etc profile — managed by sysusers at runtime
|
||||
|
||||
### Shutdown
|
||||
|
||||
```
|
||||
dinit ordered service shutdown via dependency graph
|
||||
-> shutdown-hook: seedrng (save entropy seed)
|
||||
-> exit 1 (tells dinit to handle unmounting)
|
||||
-> dinit unmounts filesystems, remounts / ro, sync, halt/reboot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The systemd->dinit Translator
|
||||
|
|
@ -254,9 +338,6 @@ option declarations) remains unchanged.
|
|||
|
||||
### systemd -> dinit mapping
|
||||
|
||||
dinit's native primitives map directly to systemd.
|
||||
Most translations become 1:1 config directives rather than shell script hacks:
|
||||
|
||||
| systemd directive | dinit equivalent |
|
||||
|---|---|
|
||||
| `ExecStart` | `command =` |
|
||||
|
|
@ -287,18 +368,8 @@ Most translations become 1:1 config directives rather than shell script hacks:
|
|||
| `WantedBy=` (empty) | service not depended on by `system` (dormant) |
|
||||
| Unix socket activation | `socket-listen =` + permissions/uid/gid |
|
||||
|
||||
Key features:
|
||||
- **Dependencies are real** — `depends-on`/`waits-for`/`after` give proper
|
||||
startup ordering and failure propagation.
|
||||
- **Service types map natively** — oneshot->scripted, forking->bgprocess, etc.
|
||||
- **Restart policy is a directive** — no generated finish scripts.
|
||||
- **Socket pre-opening** — `socket-listen =` provides basic socket activation.
|
||||
- **Capabilities** — native `capabilities =` with IAB syntax.
|
||||
|
||||
### Sandboxing (bubblewrap)
|
||||
|
||||
bwrap wraps the `command` in the dinit service file:
|
||||
|
||||
| systemd directive | bwrap equivalent |
|
||||
|---|---|
|
||||
| `ProtectSystem=strict` | `--ro-bind / /` + writable /var, /run, /tmp + declared dirs |
|
||||
|
|
@ -321,9 +392,6 @@ restore caps after uid change. These use dinit native `capabilities` instead.
|
|||
|
||||
### Timer -> snooze translation
|
||||
|
||||
`systemd.timers` and `startAt` are translated to per-timer dinit services
|
||||
using snooze (a lightweight cron alternative):
|
||||
|
||||
| systemd timerConfig | snooze flag |
|
||||
|---|---|
|
||||
| `OnCalendar` | `-d`, `-m`, `-w`, `-H`, `-M`, `-S` (parsed from calendar spec) |
|
||||
|
|
@ -333,10 +401,6 @@ using snooze (a lightweight cron alternative):
|
|||
| `OnBootSec` | `builtins.throw` (not supported) |
|
||||
| `OnUnitActiveSec` | `builtins.throw` (not supported) |
|
||||
|
||||
Each timer becomes a supervised `dinit.services."timer-<name>"` (process type,
|
||||
restart=yes). The triggered service has `autoStart = false` (started by snooze
|
||||
via `dinitctl start`).
|
||||
|
||||
### What can't be translated
|
||||
|
||||
| Feature | Status with dinit |
|
||||
|
|
@ -356,8 +420,7 @@ via `dinitctl start`).
|
|||
### systemd-sysusers (standalone)
|
||||
|
||||
Users and groups are created at boot by `systemd-sysusers` (standalone build
|
||||
from upstream systemd, statically links all systemd internals, only libc is
|
||||
dynamic). The sysusers config is generated at build time:
|
||||
from upstream systemd). The sysusers config is generated at build time:
|
||||
|
||||
```
|
||||
/etc/sysusers.d/00-minix.conf:
|
||||
|
|
@ -368,54 +431,51 @@ dynamic). The sysusers config is generated at build time:
|
|||
m root wheel
|
||||
```
|
||||
|
||||
Hashed passwords are passed via `$CREDENTIALS_DIRECTORY` (a store path linked
|
||||
from the system profile). On first boot, sysusers creates all entries. On
|
||||
subsequent boots, existing entries are preserved (merge semantics) — password
|
||||
changes via `passwd` persist across reboots.
|
||||
Hashed passwords are passed via `$CREDENTIALS_DIRECTORY`. On first boot,
|
||||
sysusers creates all entries. On subsequent boots, existing entries are
|
||||
preserved (merge semantics) — password changes via `passwd` persist.
|
||||
|
||||
### Dynamic UID/GID allocation
|
||||
### user-init service
|
||||
|
||||
Groups and users without well-known IDs get deterministic allocation:
|
||||
- Groups sorted by name, sequential GIDs from base 800
|
||||
- Users sorted by name, sequential UIDs from 800 + num_groups
|
||||
- Fallback chain: explicit UID/GID -> ids.nix lookup -> dynamic -> throw
|
||||
The `user-init` dinit service runs at boot (after `early`) and:
|
||||
1. Creates home directories + sets ownership
|
||||
2. Fixes store DB permissions (group-writable for overlay store access)
|
||||
3. Creates build log directory permissions
|
||||
4. Per interactive user (uid >= 1000):
|
||||
- Creates overlay store directories (~/.local/share/nix/)
|
||||
- Writes ~/.config/nix/nix.conf (local-overlay-store config, first-boot only)
|
||||
- Scaffolds ~/.config/home-manager/{flake.nix,home.nix} (first-boot only)
|
||||
- Sets up mount namespace with overlay store (non-fatal)
|
||||
|
||||
### Bridge from stock NixOS API
|
||||
|
||||
Translates `users.users` -> `minix.users` and `users.groups` -> `minix.groups`
|
||||
with resolved UIDs/GIDs, including `extraGroups` membership bridging. Stock
|
||||
NixOS activation scripts (Perl-based user/group management) are force-emptied.
|
||||
with resolved UIDs/GIDs, including `extraGroups` membership bridging.
|
||||
|
||||
---
|
||||
|
||||
## Standalone Tools
|
||||
|
||||
Built from upstream sources, replacing hand-rolled implementations:
|
||||
|
||||
| Tool | Source | Purpose |
|
||||
|---|---|---|
|
||||
| `systemd-tmpfiles` | systemd v260.1 standalone build | tmpfiles.d directory/symlink creation |
|
||||
| `systemd-sysusers` | systemd v260.1 standalone build | User/group creation with merge semantics |
|
||||
| `seedrng` | busybox built-in | RNG seeding with BLAKE2s mixing + entropy credit |
|
||||
| `virt-what` | nixpkgs (48 KiB) | Virtualization detection (CPUID-level, replaces shell script) |
|
||||
| `turnstile` | chimera-linux/turnstile v0.1.11 | Session tracking + per-user dinit instance spawning |
|
||||
| `hwdb.bin` | systemd v260.1 hwdb.d data + eudev udevadm | Hardware identification database (PCI/USB/Bluetooth/input) |
|
||||
| `virt-what` | nixpkgs (48 KiB) | Virtualization detection (CPUID-level) |
|
||||
| `turnstile` | chimera-linux/turnstile v0.1.11 | Session tracking + per-user dinit spawning |
|
||||
| `hwdb.bin` | systemd v260.1 hwdb.d + eudev udevadm | Hardware identification database |
|
||||
| `pam_minix_ns.so` | system/packages/pam_minix_ns.c | PAM module — enters user mount namespace at login |
|
||||
|
||||
---
|
||||
|
||||
## eudev Compatibility
|
||||
## System Commands
|
||||
|
||||
`eudev-compat.nix` presents eudev as `systemd.package` for stock NixOS modules
|
||||
that expect systemd paths:
|
||||
|
||||
- Symlinks eudev binaries and lib/udev into a wrapper derivation
|
||||
- Stubs: `systemd-sysctl` (exit 0), `systemd-run` (exec directly), `systemd-cat` (strip flags, exec)
|
||||
- Empty stubs for systemd-specific udev rules
|
||||
- `99-default.link` in `lib/systemd/network/`
|
||||
- `kmod` attribute passthrough (stage-1.nix reads `udev.kmod`)
|
||||
- tmpfiles.d configs from standalone systemd-tmpfiles build
|
||||
- Initrd fixes: dereference symlinks, provide `systemd-udevd` name
|
||||
- `hwdb.bin` compiled from systemd v260.1 hwdb.d data files using eudev's `udevadm hwdb --update`
|
||||
| Command | User | Purpose |
|
||||
|---|---|---|
|
||||
| `minix-rebuild build [FLAKE]` | root | Build system profile from /etc/minix/ and switch to it |
|
||||
| `minix-rebuild switch PATH` | root | Switch to a pre-built system profile |
|
||||
| `minix-generate-config` | root | Probe hardware, generate configuration.nix |
|
||||
| `home-manager switch --flake ~/.config/home-manager` | user | Build and activate HM generation |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -423,250 +483,134 @@ that expect systemd paths:
|
|||
|
||||
### What works (standard NixOS options)
|
||||
|
||||
These work identically to NixOS because we use the stock modules:
|
||||
|
||||
- `boot.kernelPackages`, `boot.kernelModules`, `boot.kernelParams`
|
||||
- `boot.initrd.availableKernelModules`, `boot.initrd.kernelModules`
|
||||
- `boot.blacklistedKernelModules`, `boot.extraModprobeConfig`
|
||||
- `fileSystems.*`, `swapDevices`
|
||||
- `hardware.firmware`, `hardware.enableRedistributableFirmware`
|
||||
- `hardware.deviceTree.*`
|
||||
- `hardware.cpu.amd.updateMicrocode`, `hardware.cpu.intel.updateMicrocode`
|
||||
- `services.udev.extraRules`, `services.udev.packages`
|
||||
- `environment.etc.*`, `environment.systemPackages`
|
||||
- `nixpkgs.overlays`, `nixpkgs.config`, `nixpkgs.hostPlatform`
|
||||
- `boot.kernel.sysctl.*`
|
||||
- `time.timeZone`, `i18n.defaultLocale`
|
||||
- `security.pki.certificateFiles`
|
||||
- `security.pam.services.*` (stock NixOS PAM, with SHA-512 enforced)
|
||||
- `networking.iproute2.*`
|
||||
- `networking.firewall.*` (via translated iptables service)
|
||||
- `system.stateVersion`
|
||||
- `systemd.services.*` (auto-translated to dinit)
|
||||
- `systemd.timers.*`, `startAt` (translated to snooze)
|
||||
- `systemd.tmpfiles.*` (standalone tmpfiles binary)
|
||||
- `systemd.targets.*` (wants/requires used for template instantiation)
|
||||
- `system.stateVersion`
|
||||
|
||||
A standard NixOS `hardware-configuration.nix` works as-is in MiNix.
|
||||
|
||||
### MiNix-specific options
|
||||
|
||||
| NixOS option | MiNix equivalent | Why |
|
||||
|---|---|---|
|
||||
| `users.users.*` | `minix.users.*` | sysusers standalone replaces Perl activation |
|
||||
| `users.groups.*` | `minix.groups.*` | Same |
|
||||
| `networking.hostName` | `minix.hostname` | Simpler, decoupled from networkd |
|
||||
| `dinit.services.*` | (native) | Direct dinit service definitions |
|
||||
| `minix.hardenStore` | (native) | Read-only bind mount for /nix/store |
|
||||
| `minix.turnstile.*` | (native) | Session tracking, XDG_RUNTIME_DIR, user dinit instances |
|
||||
| `minix.flakeRef` | (native) | Default flake reference for minix-rebuild build |
|
||||
| Option | Purpose |
|
||||
|---|---|
|
||||
| `minix.users.*` / `minix.groups.*` | sysusers-based user/group management |
|
||||
| `minix.hostname` | Hostname (decoupled from networkd) |
|
||||
| `minix.hardenStore` | Read-only bind mount for /nix/store |
|
||||
| `minix.turnstile.*` | Session tracking config |
|
||||
| `minix.flakeRef` | Default flake ref for minix-rebuild (default: /etc/minix) |
|
||||
| `minix.machineFlake` | Path to machine flake dir (installed to /etc/minix/) |
|
||||
| `dinit.services.*` | Native dinit service definitions |
|
||||
|
||||
Note: `users.users` and `users.groups` from stock NixOS modules are bridged
|
||||
`users.users` and `users.groups` from stock NixOS modules are bridged
|
||||
automatically to `minix.users`/`minix.groups` — both APIs work.
|
||||
|
||||
### What doesn't work
|
||||
|
||||
- `networking.interfaces.*` (scripted backend) — deeply systemd-coupled
|
||||
- `virtualisation.*` — systemd-coupled
|
||||
- `services.*` modules using `DynamicUser` or full socket activation
|
||||
- `systemd.network.*` (networkd) — blacklisted, no backend
|
||||
- `powerManagement.*` — disabled by default
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
/data/Distro/
|
||||
flake.nix Main flake: minixSystem, packages, devShell
|
||||
reference.md This document
|
||||
system/
|
||||
eval.nix Module evaluator (blacklist + evalModulesMinimal)
|
||||
overlay.nix nixpkgs overlay (strip systemd deps, enable dinit caps)
|
||||
modules/
|
||||
systemd-compat.nix optionsOnly imports + systemd->dinit translator
|
||||
dinit-services.nix dinit.services -> environment.etc."dinit.d/..."
|
||||
dinit-init.nix Init wrapper + 3-layer boot DAG + shutdown hook
|
||||
users.nix minix.users/groups + sysusers.d generation + bridge
|
||||
eudev-compat.nix eudev-as-systemd wrapper + standalone tools + initrd fixes
|
||||
toplevel.nix Assembles system profile derivation
|
||||
generate-config.nix minix-generate-config (virt-what + stock perl script)
|
||||
base-etc.nix minix.hostname, LOCALE_ARCHIVE override
|
||||
defaults.nix Feature flags, distro identity, overlay, syslogd
|
||||
rebuild.nix minix-rebuild (build + switch subcommands)
|
||||
turnstile.nix turnstile session tracking + PAM integration
|
||||
system-path.nix Busybox-based core packages
|
||||
packages/
|
||||
systemd-tmpfiles-standalone.nix Standalone tmpfiles from systemd v260.1
|
||||
systemd-sysusers-standalone.nix Standalone sysusers from systemd v260.1
|
||||
turnstile.nix turnstile v0.1.11 (session/login tracker)
|
||||
machines/
|
||||
qemu-vm/
|
||||
configuration.nix QEMU VM config (getty, sshd, dhcpcd, etc.)
|
||||
hardware-configuration.nix Detected hardware (kernel modules, filesystems)
|
||||
image/
|
||||
disk.nix Persistent qcow2 disk image + QEMU runner
|
||||
Refs/
|
||||
nixpkgs/ Shallow clone for module inspection
|
||||
dinit/ dinit source + man pages
|
||||
dinit-chimera/ Chimera Linux's dinit integration
|
||||
NixNG/modules/dinit/ NixNG's Nix-native dinit module
|
||||
systemd/ systemd v260.1 source (for standalone builds)
|
||||
seedrng/ seedrng source (reference only, busybox ships it)
|
||||
turnstile/ turnstile source (session tracker, Chimera Linux)
|
||||
flake.nix Distro flake: minixSystem, homeModules, packages
|
||||
reference.md This document
|
||||
system/
|
||||
eval.nix Module evaluator (blacklist + evalModulesMinimal)
|
||||
overlay.nix nixpkgs overlay (strip systemd deps, enable dinit caps)
|
||||
lib/
|
||||
translator.nix systemd->dinit service translator
|
||||
modules/
|
||||
systemd-compat.nix optionsOnly imports + translator wiring
|
||||
dinit-services.nix dinit.services -> environment.etc."dinit.d/..."
|
||||
dinit-init.nix Init wrapper + 3-layer boot DAG + shutdown hook
|
||||
users.nix minix.users/groups + sysusers + overlay store + HM scaffold
|
||||
eudev-compat.nix eudev-as-systemd wrapper + standalone tools + initrd fixes
|
||||
toplevel.nix Assembles system profile derivation
|
||||
generate-config.nix minix-generate-config (virt-what + stock perl script)
|
||||
base-etc.nix minix.hostname, LOCALE_ARCHIVE override
|
||||
defaults.nix Feature flags, distro identity, overlay, syslogd
|
||||
rebuild.nix minix-rebuild (build + switch)
|
||||
turnstile.nix turnstile session tracking + PAM integration
|
||||
hm-dinit.nix Home Manager module for dinit user services
|
||||
system-path.nix Busybox-based core packages
|
||||
packages/
|
||||
systemd-tmpfiles-standalone.nix Standalone tmpfiles from systemd v260.1
|
||||
systemd-sysusers-standalone.nix Standalone sysusers from systemd v260.1
|
||||
turnstile.nix turnstile v0.1.11 (session/login tracker)
|
||||
pam-minix-ns.nix PAM module for mount namespace entry
|
||||
pam_minix_ns.c PAM module C source
|
||||
machines/
|
||||
qemu-vm/
|
||||
flake.nix Machine flake (git+https://...MiNix, system only)
|
||||
configuration.nix QEMU VM config (getty, sshd, dhcpcd, etc.)
|
||||
hardware-configuration.nix Detected hardware (kernel modules, filesystems)
|
||||
image/
|
||||
disk.nix Persistent qcow2 disk image + QEMU runner
|
||||
Refs/
|
||||
nixpkgs/ Shallow clone for module inspection
|
||||
dinit/ dinit source + man pages
|
||||
dinit-chimera/ Chimera Linux's dinit integration
|
||||
NixNG/modules/dinit/ NixNG's Nix-native dinit module
|
||||
turnstile/ turnstile source (Chimera Linux)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## nixpkgs Overlay
|
||||
## Known Optimization Opportunities
|
||||
|
||||
```nix
|
||||
final: prev: {
|
||||
procps = prev.procps.override { withSystemd = false; };
|
||||
util-linux = prev.util-linux.override { systemdSupport = false; };
|
||||
openssh = prev.openssh.override { withFIDO = false; };
|
||||
dinit = prev.dinit.overrideAttrs (old: {
|
||||
buildInputs = (old.buildInputs or []) ++ [ prev.libcap ];
|
||||
configureFlags = (old.configureFlags or []) ++ [ "--enable-capabilities" ];
|
||||
});
|
||||
}
|
||||
```
|
||||
### nixpkgs source duplication (~444 MB)
|
||||
The nixpkgs source tree is not part of the system closure (only package
|
||||
outputs are). When a user evaluates their HM flake, nix fetches and unpacks
|
||||
the full nixpkgs source into the overlay upper layer. Fix: add nixpkgs source
|
||||
to system closure via `system.extraDependencies` so it's in the lower store.
|
||||
|
||||
Applied via `nixpkgs.overlays` in defaults.nix. Strips systemd linkage from
|
||||
key packages. dinit built with `--enable-capabilities` for native IAB support.
|
||||
Uses a separate `hostPkgs` (without overlay) for build tools to avoid cache misses.
|
||||
### glibc-locales duplication (~222 MB)
|
||||
The systemd-stripping overlay changes the derivation graph enough to produce
|
||||
a different glibc-locales hash than "clean" nixpkgs. Users get a second copy.
|
||||
Fix: investigate overlay impact on locale derivation chain.
|
||||
|
||||
### .drv file accumulation (~1280 files)
|
||||
Nix evaluation instantiates all referenced derivations in the store. In the
|
||||
overlay store, these accumulate in the upper layer. Normal nix behavior —
|
||||
visible because overlay makes the user's additions explicit.
|
||||
|
||||
---
|
||||
|
||||
## Flake Outputs
|
||||
|
||||
```nix
|
||||
{
|
||||
lib.minixSystem = minixSystem; # For external consumers
|
||||
packages.x86_64-linux = {
|
||||
system = systemProfile; # Just the system profile
|
||||
vm = diskImage; # qcow2 disk + QEMU runner
|
||||
default = diskImage;
|
||||
};
|
||||
devShells.x86_64-linux.default = ...; # qemu, cpio, gzip, etc.
|
||||
}
|
||||
```
|
||||
|
||||
### Build & test
|
||||
|
||||
```bash
|
||||
nix build .#vm # Build disk image + runner
|
||||
./result/bin/run-minix-vm # Boot in QEMU
|
||||
ssh -p 2222 root@localhost # SSH into VM (empty password)
|
||||
dinitctl list # Check services inside VM
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Design Rules
|
||||
|
||||
1. **Reuse NixOS modules wherever possible.** Use stock modules as-is via
|
||||
optionsOnly or direct import. Only write from scratch where NixOS is
|
||||
structurally incompatible.
|
||||
|
||||
2. **Translate, don't rewrite.** The systemd->dinit translator gives access
|
||||
to the entire NixOS service ecosystem automatically. dinit's native
|
||||
primitives make most translations 1:1 config directives.
|
||||
|
||||
3. **Mutable files with merge semantics.** /etc files with `.mode` sidecar
|
||||
are preserved across reboots (early-etc only writes on first boot).
|
||||
passwd/shadow/group/gshadow managed by sysusers with entry-level merge —
|
||||
runtime changes via `passwd` persist.
|
||||
|
||||
4. **Sandboxing matters.** Bubblewrap provides real namespace isolation
|
||||
equivalent to systemd's security directives. dinit's native capabilities
|
||||
and no-new-privs complement bwrap.
|
||||
|
||||
5. **Keep it minimal.** dinit + busybox + eudev base. No systemd runtime.
|
||||
No Nix daemon by default.
|
||||
|
||||
6. **Use standalone tools.** Prefer standalone builds (systemd-tmpfiles,
|
||||
systemd-sysusers) and busybox builtins (seedrng) over hand-rolled code.
|
||||
|
||||
---
|
||||
|
||||
## Key Tradeoffs
|
||||
|
||||
### What we lose vs NixOS
|
||||
- Live system switching (we require reboot for system profile changes)
|
||||
- DynamicUser (needs ephemeral UID allocator)
|
||||
- Full sd_listen_fds socket activation (dinit covers Unix sockets)
|
||||
- networkd, resolved, journald (use scripted networking, dhcpcd, syslogd)
|
||||
- Monotonic timers (OnBootSec, etc. — calendar only via snooze)
|
||||
- Shared binary cache between users (each user has own store)
|
||||
|
||||
### What we gain
|
||||
- No systemd runtime
|
||||
- No Nix daemon (simpler, fewer moving parts, smaller attack surface)
|
||||
- Minimal base (dinit + busybox + eudev)
|
||||
- Parallel dependency-ordered boot (3-layer dinit DAG)
|
||||
- Readiness notification for services
|
||||
- Native capabilities, cgroup placement, rlimits in the init
|
||||
- Full control over every layer
|
||||
- Access to ~80-85% of NixOS service modules via the translator
|
||||
- Real sandboxing via bubblewrap + dinit native security
|
||||
- Standard hardware-configuration.nix compatibility
|
||||
- Per-user isolation (separate stores, separate dinit instances)
|
||||
- Proper user merge semantics (sysusers — password changes persist)
|
||||
|
||||
---
|
||||
|
||||
## Development Roadmap
|
||||
## Development Status
|
||||
|
||||
### Done
|
||||
- [x] System profile via evalModulesMinimal + full NixOS module set
|
||||
- [x] systemd->dinit translator with bwrap sandboxing
|
||||
- [x] Timer->snooze translation (calendar timers, RandomizedDelaySec, Persistent)
|
||||
- [x] AmbientCapabilities -> dinit native IAB capabilities
|
||||
- [x] Socket activation for Unix sockets (socket-listen)
|
||||
- [x] PIDFile, wants translation, rlimits (nofile, core, data, addrspace)
|
||||
- [x] Template services (getty@, serial-getty@, autovt@) with native dinit `$1`
|
||||
- [x] Socket activation for Unix sockets
|
||||
- [x] Template services (getty@, serial-getty@, autovt@) with native dinit $1
|
||||
- [x] User/group management with sysusers + dynamic allocation + NixOS bridge
|
||||
- [x] eudev compatibility layer + standalone tools (tmpfiles, sysusers)
|
||||
- [x] Persistent qcow2 disk image builder
|
||||
- [x] minix-generate-config (virt-what) and minix-rebuild tools
|
||||
- [x] dinit-init.nix — 3-layer boot DAG (early->system->boot) + shutdown hook
|
||||
- [x] seedrng (busybox built-in) for entropy management
|
||||
- [x] Serial console detection via kernel params (no udev deadlock)
|
||||
- [x] minix-generate-config and minix-rebuild tools
|
||||
- [x] 3-layer boot DAG (early->system->boot) + shutdown hook
|
||||
- [x] Serial console detection via kernel params
|
||||
- [x] Mutable /etc with first-boot-only writes + sysusers merge semantics
|
||||
- [x] VM-tested: boot, reboot, SSH, password persistence, service ordering
|
||||
- [x] nix-daemon suppressed (optionsOnly — no daemon service, no nixbld users)
|
||||
- [x] turnstile session tracking (per-user dinit instances, XDG_RUNTIME_DIR)
|
||||
- [x] PAM integration (pam_turnstile.so in login/sshd/su/sudo)
|
||||
- [x] minix-rebuild enhanced (build + switch subcommands, configurable flake ref)
|
||||
- [x] VM-tested: turnstiled running, user dinit instance, XDG_RUNTIME_DIR=/run/user/$UID
|
||||
- [x] hwdb.bin compiled from systemd hwdb.d data (11 MB, eudev device identification working)
|
||||
- [x] systemd-cat stub (strips journal flags, execs command — for X11 display manager modules)
|
||||
|
||||
### Next: per-user Nix stores + Home Manager
|
||||
- [ ] User store: per-user Nix store paths (~/.local/share/nix/)
|
||||
- [ ] Home Manager integration with per-user stores
|
||||
- [ ] System-provided user services (D-Bus session bus, PipeWire via /etc/dinit.d/user/)
|
||||
- [x] nix-daemon suppressed (no daemon, no nixbld users)
|
||||
- [x] turnstile session tracking + PAM integration
|
||||
- [x] hwdb.bin + systemd-cat stub
|
||||
- [x] Per-user overlay stores (local-overlay-store, mount namespace, pam_minix_ns.so)
|
||||
- [x] Flake architecture: distro flake (build tooling) + machine flake (/etc/minix/)
|
||||
- [x] Home Manager integration (user flake auto-scaffolded, follows distro pins)
|
||||
- [x] VM-tested: full pipeline — boot, overlay store, nix run, home-manager switch
|
||||
|
||||
### Future
|
||||
- [ ] Optimize: preload nixpkgs/HM source into system closure
|
||||
- [ ] Optimize: fix glibc-locales derivation divergence from overlay
|
||||
- [ ] System-provided user services (D-Bus session bus, PipeWire)
|
||||
- [ ] Board support (Rockchip SBCs, SD card images)
|
||||
- [ ] GRUB bootloader (currently extlinux only)
|
||||
- [ ] ISO for generic x86 install
|
||||
- [ ] Seccomp filter generation (SystemCallFilter -> BPF)
|
||||
- [ ] Live system switching without reboot (stretch goal)
|
||||
- [ ] Rewrite minix-generate-config in shell (drop Perl dependency)
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
```
|
||||
Refs/
|
||||
nixpkgs/ Shallow clone of nixpkgs for module inspection
|
||||
dinit/ dinit source + man pages (service file format spec)
|
||||
dinit-chimera/ Chimera Linux's dinit system integration (production reference)
|
||||
NixNG/ NixNG — has a Nix-native dinit module (modules/dinit/)
|
||||
systemd/ systemd v260.1 source (standalone tmpfiles + sysusers builds)
|
||||
seedrng/ seedrng source by Jason Donenfeld (reference; busybox ships it)
|
||||
turnstile/ turnstile source (session/login tracker, Chimera Linux)
|
||||
```
|
||||
- [ ] Live system switching without reboot
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
# as a distro default so all MiNix systems support overlay stores.
|
||||
nix.settings.experimental-features = lib.mkDefault [ "nix-command" "flakes" "local-overlay-store" ];
|
||||
|
||||
# git is needed by nix's git+https:// fetcher (used by machine and user flakes).
|
||||
environment.systemPackages = [ pkgs.gitMinimal ];
|
||||
|
||||
# vconsole-setup is handled by systemd-vconsole-setup.service which
|
||||
# we don't have. The reload service calls systemctl — disable it.
|
||||
systemd.services.reload-systemd-vconsole-setup.enable = lib.mkDefault false;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# minix-rebuild — build and/or switch the system profile.
|
||||
# minix-home — scaffold per-user Home Manager config.
|
||||
# Installs the machine flake to /etc/minix/ as mutable files (first-boot-only).
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
|
|
@ -72,56 +71,6 @@ in {
|
|||
;;
|
||||
esac
|
||||
'')
|
||||
# minix-home — scaffold user Home Manager config
|
||||
(pkgs.writeShellScriptBin "minix-home" ''
|
||||
set -e
|
||||
HM_DIR="''${HOME}/.config/home-manager"
|
||||
|
||||
case "''${1:-}" in
|
||||
init)
|
||||
if [ -f "$HM_DIR/flake.nix" ]; then
|
||||
echo "''${HM_DIR}/flake.nix already exists. Remove it first to re-init."
|
||||
exit 1
|
||||
fi
|
||||
USERNAME="$(id -un)"
|
||||
HOMEDIR="$HOME"
|
||||
ARCH="${pkgs.stdenv.hostPlatform.system}"
|
||||
mkdir -p "$HM_DIR"
|
||||
cat > "$HM_DIR/flake.nix" << 'FLAKE'
|
||||
{
|
||||
inputs = {
|
||||
minix.url = "git+https://git.axiomania.org/lebowski/MiNix.git";
|
||||
nixpkgs.follows = "minix/nixpkgs-stable";
|
||||
home-manager.follows = "minix/home-manager";
|
||||
};
|
||||
outputs = { minix, nixpkgs, home-manager, ... }: {
|
||||
homeConfigurations."MINIX_USERNAME" = home-manager.lib.homeManagerConfiguration {
|
||||
pkgs = nixpkgs.legacyPackages.MINIX_ARCH;
|
||||
modules = [ minix.homeModules.default ./home.nix ];
|
||||
};
|
||||
};
|
||||
}
|
||||
FLAKE
|
||||
${pkgs.gnused}/bin/sed -i "s|MINIX_USERNAME|$USERNAME|;s|MINIX_ARCH|$ARCH|" "$HM_DIR/flake.nix"
|
||||
cat > "$HM_DIR/home.nix" << HOMENIX
|
||||
{ pkgs, ... }: {
|
||||
home.username = "$USERNAME";
|
||||
home.homeDirectory = "$HOMEDIR";
|
||||
home.stateVersion = "25.11";
|
||||
programs.home-manager.enable = true;
|
||||
}
|
||||
HOMENIX
|
||||
echo "Created $HM_DIR/flake.nix and $HM_DIR/home.nix"
|
||||
echo "Edit home.nix, then run: home-manager switch --flake $HM_DIR"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: minix-home init"
|
||||
echo ""
|
||||
echo "Scaffolds ~/.config/home-manager/ with a starter flake + home.nix."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
'')
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,33 @@ let
|
|||
experimental-features = nix-command flakes local-overlay-store
|
||||
'';
|
||||
|
||||
# Per-user HM flake (mutable — only created on first boot)
|
||||
mkUserFlake = u: pkgs.writeText "hm-flake-${u.name}" ''
|
||||
{
|
||||
inputs = {
|
||||
minix.url = "git+https://git.axiomania.org/lebowski/MiNix.git";
|
||||
nixpkgs.follows = "minix/nixpkgs-stable";
|
||||
home-manager.follows = "minix/home-manager";
|
||||
};
|
||||
outputs = { minix, nixpkgs, home-manager, ... }: {
|
||||
homeConfigurations."${u.name}" = home-manager.lib.homeManagerConfiguration {
|
||||
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||
modules = [ minix.homeModules.default ./home.nix ];
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
|
||||
# Per-user starter home.nix (mutable — only created on first boot)
|
||||
mkUserHomeNix = u: pkgs.writeText "home-${u.name}" ''
|
||||
{ pkgs, ... }: {
|
||||
home.username = "${u.name}";
|
||||
home.homeDirectory = "${u.home}";
|
||||
home.stateVersion = "25.11";
|
||||
programs.home-manager.enable = true;
|
||||
}
|
||||
'';
|
||||
|
||||
in {
|
||||
options = {
|
||||
minix.users = mkOption {
|
||||
|
|
@ -313,6 +340,11 @@ in {
|
|||
chmod 0660 /nix/var/nix/db/big-lock
|
||||
chmod 0664 /nix/var/nix/db/db.sqlite-shm /nix/var/nix/db/db.sqlite-wal
|
||||
|
||||
# Build log directory — nix writes build logs here during derivation builds.
|
||||
mkdir -p /nix/var/log/nix/drvs
|
||||
chgrp -R users /nix/var/log/nix
|
||||
chmod -R 0775 /nix/var/log/nix
|
||||
|
||||
${concatLines (mapAttrsToList (name: u: let
|
||||
nixDir = "${u.home}/.local/share/nix";
|
||||
configDir = "${u.home}/.config";
|
||||
|
|
@ -330,7 +362,19 @@ in {
|
|||
chmod 644 "${configDir}/nix/nix.conf"
|
||||
fi
|
||||
|
||||
chown -R ${toString u.uid}:${toString u.gid} "${configDir}/nix"
|
||||
# Per-user HM config (mutable — only create if missing)
|
||||
mkdir -p "${configDir}/home-manager"
|
||||
if [ ! -f "${configDir}/home-manager/flake.nix" ]; then
|
||||
cp ${mkUserFlake u} "${configDir}/home-manager/flake.nix"
|
||||
chmod 644 "${configDir}/home-manager/flake.nix"
|
||||
fi
|
||||
if [ ! -f "${configDir}/home-manager/home.nix" ]; then
|
||||
cp ${mkUserHomeNix u} "${configDir}/home-manager/home.nix"
|
||||
chmod 644 "${configDir}/home-manager/home.nix"
|
||||
fi
|
||||
|
||||
chown ${toString u.uid}:${toString u.gid} "${configDir}"
|
||||
chown -R ${toString u.uid}:${toString u.gid} "${configDir}/nix" "${configDir}/home-manager"
|
||||
|
||||
# --- Mount namespace with overlay store ---
|
||||
# Strategy: start a helper in a new mount ns, bind-mount the ns
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue