Files
ctrld/cmd/cli/service_image_path_windows.go
T
Cuong Manh Le 084c785ed5 cmd/cli: report whether ctrld finished starting up, not just what SCM thinks
"ctrld status" reported the service manager's view and nothing else, so it
printed "Service is running" and exited 0 for a process that was alive and
registered as started but had never got past startup: no control socket, no DNS
listener, no policy applied. The one command an operator reaches for first
confirmed the service was fine while the host had no working DNS.

Probe the control server's /started endpoint before reporting success. That
endpoint only answers once the onStarted hooks have completed, which is after the
listeners are up, so a successful probe means the process is serving rather than
merely alive. A service that is registered as running but cannot confirm startup
is now reported as such, with a pointer to the log, and exits 3 - distinct from
stopped (1) and unknown (2), because it needs a different response.

A probe blocked by permissions is not evidence of a broken service: an
unprivileged caller still gets "Service is running", with a note that startup was
not verified. The probe is bounded by a short timeout so status stays fast.

Document the exit codes in the command's help, and cover the probe (ready, not
finished starting, no socket, timed out) and the classification, including that
an unreadable socket is not reported as a failure.

The not-ready verdict is only reported when the probe could have found the
daemon's socket. socketDir() is caller-relative on unix - the system directory
when writable, the caller's home otherwise - so an unprivileged "ctrld status"
looks somewhere the root-owned daemon never listened and gets ENOENT, which is
"wrong path", not "not ready". Since only darwin has an elevation PreRun and the
root-level alias has none, that is the normal invocation; reporting exit 3 there
would have told a monitoring check to restart healthy daemons. Such a caller now
gets the service manager's view with startup reported as unverified. Windows and
mobile resolve the same directory for every caller, so the verdict stays fully
available on the platform the hung start was seen on. A successful probe is still
conclusive whoever ran it.
2026-08-21 14:50:27 +07:00

42 lines
1.3 KiB
Go

//go:build windows
package cli
import (
"os"
"golang.org/x/sys/windows/registry"
)
// installedServiceDirMatches reports whether this executable is the installed service
// binary, by comparing its directory with the one in the service's registered ImagePath.
//
// socketDir() on Windows is relative to the running executable, so a ctrld.exe run from
// somewhere else - a download directory, a build tree - looks for the control socket in
// its own directory and never finds the installed daemon's. A failed probe from there
// says nothing about the service's health, and reporting "not ready" for it would tell
// monitoring to restart a healthy service.
//
// Anything unreadable answers true, keeping the previous behaviour: readiness stays
// verifiable unless there is positive evidence of a different install.
func installedServiceDirMatches() bool {
self, err := os.Executable()
if err != nil {
return true
}
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Services\`+ctrldServiceName, registry.QUERY_VALUE)
if err != nil {
return true
}
defer key.Close()
imagePath, _, err := key.GetStringValue("ImagePath")
if err != nil {
return true
}
installed := serviceBinaryFromImagePath(imagePath)
if installed == "" {
return true
}
return sameExecutableDir(installed, self)
}