openvibers/openvibe.link Commits

Fix latch file ownership after a root stop/resume without a running node; log files on macOS; honest log docs

OP OpenVibers committed 29 Sept 2026 · 0816534eee · 3 files, +11 −2


Changes

ddiff --git a/cmd/openvibe-node/main.go b/cmd/openvibe-node/main.go
iindex e667771..c6ef81d 100644
---- a/cmd/openvibe-node/main.go
++++ b/cmd/openvibe-node/main.go
@@@ -331,6 +331,7 @@ func cmdStop(g *globals, stdout io.Writer) error {
if ferr := safety.WriteLocalFile(g.paths.LatchFile(), true); ferr != nil {
return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)
}
++ chownLikeDir(g.paths.LatchFile(), g.paths.StateDir) // the service account must be able to read it
fmt.Fprintln(stdout, "The node did not answer; the stop is latched in", g.paths.LatchFile())
fmt.Fprintln(stdout, "A running node obeys it within a quarter second; a starting node starts stopped. Release with `openvibe-node resume`.")
return nil
@@@ -342,6 +343,7 @@ func cmdResume(g *globals, stdout io.Writer) error {
if ferr := safety.WriteLocalFile(g.paths.LatchFile(), false); ferr != nil {
return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)
}
++ chownLikeDir(g.paths.LatchFile(), g.paths.StateDir)
}
fmt.Fprintln(stdout, "Resumed: the local stop and any server e-stop are released. Operators can drive again.")
return nil
ddiff --git a/docs/install.md b/docs/install.md
iindex 558ebbf..5049f6b 100644
---- a/docs/install.md
++++ b/docs/install.md
@@@ -128,7 +128,8 @@ internet (Ethernet, or a second Wi-Fi adapter). Install with `--robot cozmo`; th
- `openvibe-node status` shows the last link error. "the server refused the device credential" means it was revoked:
`sudo openvibe-node pair --force <NEW-CODE>`.
--- Logs: `journalctl -u openvibe-node -f` (Linux), `/var/log/openvibe-node.*.log` (macOS), Event Viewer (Windows).
++- Logs: `journalctl -u openvibe-node -f` (Linux), `/usr/local/var/log/openvibe-node.err.log` (macOS). On Windows the
++ service's log is not kept yet; stop the service and run `openvibe-node run` in a terminal to watch it.
- A plugin in `faulted` state says why in `status` (missing library, not a Raspberry Pi, robot not reachable, firmware).
- `openvibe-node plugins` works without the service running: it asks each plugin to describe itself without touching
hardware.
ddiff --git a/internal/service/service.go b/internal/service/service.go
iindex 4429014..076df26 100644
---- a/internal/service/service.go
++++ b/internal/service/service.go
@@@ -5,6 +5,7 @@ package service
import (
"context"
"errors"
++ "runtime"
"sync"
"time"
@@@ -73,7 +74,7 @@ type Options struct {
}
func config(opt Options) *ks.Config {
-- return &ks.Config{
++ c := &ks.Config{
Name: Name, DisplayName: DisplayName, Description: Description, Arguments: opt.Arguments, UserName: opt.UserName,
Option: ks.KeyValue{
"Restart": "always", // systemd
@@@ -85,6 +86,11 @@ func config(opt Options) *ks.Config {
"DelayedAutoStart": false,
},
}
++ if runtime.GOOS == "darwin" {
++ // launchd has no journal: write /usr/local/var/log/openvibe-node.{out,err}.log. systemd keeps journald.
++ c.Option["LogOutput"] = true
++ }
++ return c
}
// Run runs program under the service manager, or in the foreground when started from a terminal.