Files
mesh-controller/cmd/mesh-controller/selfexec.go
T
jochen 6c7af5c63f
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
Run a verb from the controller's own running image, and refuse what it cannot run as a handover (hq issue 289)
The witness moves a running build aside into a directory the controller's user
cannot enter, then deletes it; a verb exec'd from os.Executable() in that window
failed with permission denied. /proc/self/exe stays valid while the process lives.
A verb that still cannot start, or arrives while the controller stops, is refused
with link.ErrHandingOver and marked retry: handing-over.
2026-10-07 02:45:09 +02:00

47 lines
1.8 KiB
Go

package main
import (
"context"
"os"
"os/exec"
"runtime"
"sync/atomic"
)
// startedFrom is the path this process's executable had when it started: what a verb's command line
// is named in a process listing, and what is run where the image cannot be named otherwise.
var startedFrom, _ = os.Executable()
// ownImage is how a process names the executable it is running, as long as it runs, wherever the file
// has gone since. On Linux the kernel keeps it: /proc/self/exe is the running image itself, not a path,
// so it is valid after the file is renamed into a directory this process may not enter, or deleted —
// which is what the node-engine's witness does to a build it replaces (novox/hq issue 289). Read in the
// child, it names the child's image, which until the exec is this process's.
//
// os.Executable reads the same link and returns the path it points at *now*: correct at start and
// wrong the moment the file moves, which is the fault. A variable so a test can name another.
var ownImage = func() string {
if runtime.GOOS == "linux" {
if _, err := os.Stat("/proc/self/exe"); err == nil {
return "/proc/self/exe"
}
}
return startedFrom
}
// selfCommand is this binary run with a command line: the image this process runs, named in a process
// listing as the path it started from.
func selfCommand(ctx context.Context, argv []string) *exec.Cmd {
cmd := exec.CommandContext(ctx, ownImage(), argv...)
if startedFrom != "" {
cmd.Args[0] = startedFrom
}
return cmd
}
// handingOver is set when the serving controller begins to stop — a signal from its supervisor, a lease
// lost. From then a verb that would run a command is refused as a handover rather than started and
// killed with this process: the caller asks again, and the controller after this one answers
// (novox/hq issue 289).
var handingOver atomic.Bool