15cc71755519
read system generations from profile symlinks instead of nix-env --list-generations (avoids root-only profile lock); fixes history/gen current/diff/status gen as non-root
- time
- 2026-06-04 23:01 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- non-root generation read
- parent
- 41b75b265eb0
↓ nina-15cc7175.tar.gzatlas at this save
files changed1 file
src/exec.zig+12 −1src/exec.zig+12 −1
@@ -145,8 +145,19 @@145145 146146 // --- Generations ---147147 148+// Read system-profile generations WITHOUT root. `nix-env --list-generations -p149+// /nix/var/nix/profiles/system` takes a profile lock and fails as a normal user150+// ("system.lock: Permission denied"). The generation symlinks themselves are151+// world-readable, so list them directly: parse `system-N-link` names, take each152+// link's own mtime for the date/time, and mark the one the `system` symlink153+// points at as current. Output matches the `nix-env --list-generations` columns154+// (num date time [current]) so parseGenerations is unchanged.155+const GEN_LIST_SCRIPT =156+ \\cur=$(readlink /nix/var/nix/profiles/system 2>/dev/null | sed 's/.*system-\([0-9]*\)-link/\1/'); find /nix/var/nix/profiles -maxdepth 1 -name 'system-*-link' -printf '%f %TY-%Tm-%Td %TH:%TM\n' 2>/dev/null | sed 's/system-\([0-9]*\)-link/\1/' | sort -n | awk -v c="$cur" '{ if ($1==c) print $0" current"; else print $0 }'157+;158+148159 pub fn getGenerations(gpa: std.mem.Allocator, io: std.Io, machine: *const types.Machine) ![]types.GenerationInfo {149- const r = try capture(gpa, io, machine, &.{ "nix-env", "-p", SYSTEM_PROFILE, "--list-generations" });160+ const r = try capture(gpa, io, machine, &.{ "sh", "-c", GEN_LIST_SCRIPT });150161 defer gpa.free(r.stderr);151162 defer gpa.free(r.stdout);152163 if (r.exit_code != 0) return error.ProcessFailed;