Portable install: the binary installs itself; static builds on five architectures; root via sudo, doas or uid 0; every package manager; older systemd; no lsblk
- hamlab install / uninstall (internal/setup): systemd or OpenRC, elevates through sudo or doas, runs as the invoking user, sets or generates the password, names only journal groups that exist, waits for /healthz, reports an active firewalld/ufw. --purge and the data chown never touch a directory that isn't Ham Lab's alone. - install.sh: curl-able bootstrap (arch detection, SHA256SUMS, offline beside the binaries, noexec /tmp fallback). make release builds dist/ for amd64, arm64, arm (ARMv6), 386, riscv64. Every build is CGO_ENABLED=0; the native one used to link glibc. - internal/priv replaces every literal `sudo -n`: uid 0, sudo or doas. - Updates acts on dnf, zypper, pacman and apk as well as apt; dnf shows installed versions. - Services falls back to the plain systemctl table before systemd 246 and says so on hosts without systemd. Disks falls back to /sys/block without lsblk. - Listener binds with IP_FREEBIND, so a LAN address that isn't up at boot is no failure. - Self-update: the new build must pass `check` against the live config, is put in place by atomic rename, and the daemon re-execs itself (same under any supervisor). - State and config writes are fsynced; a corrupt state.json is set aside, not fatal. - Terminal shutdown no longer empties the saved list, so names come back after a restart by design rather than by winning a race. - Config default is ~/.config/hamlab; an existing ~/apps/hamlab is still found. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
91b7f4f009
commit
488d929733
@@ -9,6 +9,7 @@ import (
|
||||
"os/exec"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -68,6 +69,7 @@ type Manager struct {
|
||||
shell string
|
||||
home string
|
||||
OnChange func([]Info) // called (without locks held) when the list changes
|
||||
closing atomic.Bool
|
||||
}
|
||||
|
||||
func NewManager(shell, home string) *Manager {
|
||||
@@ -283,13 +285,15 @@ func (m *Manager) Close(id string) error {
|
||||
}
|
||||
|
||||
func (m *Manager) changed() {
|
||||
if m.OnChange != nil {
|
||||
if m.OnChange != nil && !m.closing.Load() {
|
||||
m.OnChange(m.List())
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown hangs up every shell. Called on daemon exit.
|
||||
// Shutdown hangs up every shell. Called on daemon exit. The saved list is left as it
|
||||
// was, because that list is what the next start re-opens.
|
||||
func (m *Manager) Shutdown() {
|
||||
m.closing.Store(true)
|
||||
for _, s := range m.List() {
|
||||
_ = m.Close(s.ID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user