"ctrld status" reported the service manager's view and nothing else, so it
printed "Service is running" and exited 0 for the incident's process: alive,
registered as started, stuck in API preflight, with no control socket, no DNS
listener and 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.
- Add entry/exit logging to all ServiceCommand methods (start, stop, status, reload, restart, uninstall)
- Replace mainLog.Load() calls with consistent logger variable usage throughout
- Capitalize all logging messages for better readability
- Add error context logging for service manager initialization failures
- Add debug logging for key operations (restart sequence, cleanup, validation)
- Improve error handling with proper error context in all service commands
- Add completion logging to track command execution flow
This improves debugging capabilities and provides better operational visibility
for service management operations while maintaining clean user-facing messages.
- Split initializeServiceManager into two methods:
* initializeServiceManager(): Simple method using default configuration
* initializeServiceManagerWithServiceConfig(): Advanced method for custom config
- Simplify NewServiceCommand() to return *ServiceCommand without error
- Update all service command methods to use appropriate initialization:
* Start: Uses initializeServiceManagerWithServiceConfig() for custom args
* Stop/Restart/Reload/Status/Uninstall: Use simple initializeServiceManager()
- Remove direct access to sc.serviceManager.svc/prog in favor of lazy initialization
- Improve separation of concerns and reduce code duplication
- Move ServiceCommand.Start to commands_service_start.go
- Move ServiceCommand.Stop to commands_service_stop.go
- Move ServiceCommand.Restart to commands_service_restart.go
- Move ServiceCommand.Reload to commands_service_reload.go
- Move ServiceCommand.Status to commands_service_status.go
- Move ServiceCommand.Uninstall to commands_service_uninstall.go
- Move createStartCommands to commands_service_start.go
- Clean up imports in commands_service.go
- Remove all method implementations from main service file
This refactoring improves code organization by:
- Separating concerns into focused files
- Making navigation easier for developers
- Reducing merge conflicts between different commands
- Following consistent modular patterns
- Reducing commands_service.go from ~650 lines to ~50 lines
Each method is now co-located with its related functionality,
making the codebase more maintainable and easier to understand.