feat(app): resolve daemon self-exec path per OS
- commit
- eba0b225d67a9af0e00f9972799e309ea0eb2c60
- author
- brice · · 2026-07-16 17:43 UTC
- parent
- d2d212f
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +37 -1
A internal/app/selfexe_darwin.go +9 -0
| @@ -0,0 +1,9 @@ | |||
| 1 | + | //go:build darwin | |
| 2 | + | ||
| 3 | + | package app | |
| 4 | + | ||
| 5 | + | import "os" | |
| 6 | + | ||
| 7 | + | func selfExePath() (string, error) { | |
| 8 | + | return os.Executable() | |
| 9 | + | } | |
| @@ -0,0 +1,9 @@ | |||||
| 1 | + | //go:build darwin | |||
| 2 | + | ||||
| 3 | + | package app | |||
| 4 | + | ||||
| 5 | + | import "os" | |||
| 6 | + | ||||
| 7 | + | func selfExePath() (string, error) { | |||
| 8 | + | return os.Executable() | |||
| 9 | + | } | |||
A internal/app/selfexe_linux.go +7 -0
| @@ -0,0 +1,7 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package app | |
| 4 | + | ||
| 5 | + | func selfExePath() (string, error) { | |
| 6 | + | return "/proc/self/exe", nil | |
| 7 | + | } | |
| @@ -0,0 +1,7 @@ | |||||
| 1 | + | //go:build linux | |||
| 2 | + | ||||
| 3 | + | package app | |||
| 4 | + | ||||
| 5 | + | func selfExePath() (string, error) { | |||
| 6 | + | return "/proc/self/exe", nil | |||
| 7 | + | } | |||
A internal/app/selfexe_linux_test.go +15 -0
| @@ -0,0 +1,15 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package app | |
| 4 | + | ||
| 5 | + | import "testing" | |
| 6 | + | ||
| 7 | + | func TestSelfExePath(t *testing.T) { | |
| 8 | + | got, err := selfExePath() | |
| 9 | + | if err != nil { | |
| 10 | + | t.Fatalf("selfExePath: %v", err) | |
| 11 | + | } | |
| 12 | + | if got != "/proc/self/exe" { | |
| 13 | + | t.Fatalf("selfExePath = %q, want %q", got, "/proc/self/exe") | |
| 14 | + | } | |
| 15 | + | } | |
| @@ -0,0 +1,15 @@ | |||||
| 1 | + | //go:build linux | |||
| 2 | + | ||||
| 3 | + | package app | |||
| 4 | + | ||||
| 5 | + | import "testing" | |||
| 6 | + | ||||
| 7 | + | func TestSelfExePath(t *testing.T) { | |||
| 8 | + | got, err := selfExePath() | |||
| 9 | + | if err != nil { | |||
| 10 | + | t.Fatalf("selfExePath: %v", err) | |||
| 11 | + | } | |||
| 12 | + | if got != "/proc/self/exe" { | |||
| 13 | + | t.Fatalf("selfExePath = %q, want %q", got, "/proc/self/exe") | |||
| 14 | + | } | |||
| 15 | + | } | |||
M internal/app/spawn.go +6 -1
| @@ -157,13 +157,18 @@ func realDial(ctx context.Context, dir string) (ports.Transport, error) { | |||
| 157 | 157 | // and never writes to the client's terminal. It logs via slog to the shared | |
| 158 | 158 | // log file instead. | |
| 159 | 159 | func realSpawn() error { | |
| 160 | + | exePath, err := selfExePath() | |
| 161 | + | if err != nil { | |
| 162 | + | return fmt.Errorf("resolving executable path: %w", err) | |
| 163 | + | } | |
| 164 | + | ||
| 160 | 165 | devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) | |
| 161 | 166 | if err != nil { | |
| 162 | 167 | return fmt.Errorf("opening %s: %w", os.DevNull, err) | |
| 163 | 168 | } | |
| 164 | 169 | defer func() { _ = devNull.Close() }() | |
| 165 | 170 | ||
| 166 | - | cmd := exec.Command("/proc/self/exe", "--daemon") | |
| 171 | + | cmd := exec.Command(exePath, "--daemon") | |
| 167 | 172 | cmd.Dir = platform.DirOrHome("") | |
| 168 | 173 | cmd.Stdin = devNull | |
| 169 | 174 | cmd.Stdout = devNull | |
| @@ -157,13 +157,18 @@ func realDial(ctx context.Context, dir string) (ports.Transport, error) { | |||||
| 157 | // and never writes to the client's terminal. It logs via slog to the shared | 157 | // and never writes to the client's terminal. It logs via slog to the shared | ||
| 158 | // log file instead. | 158 | // log file instead. | ||
| 159 | func realSpawn() error { | 159 | func realSpawn() error { | ||
| 160 | + | exePath, err := selfExePath() | |||
| 161 | + | if err != nil { | |||
| 162 | + | return fmt.Errorf("resolving executable path: %w", err) | |||
| 163 | + | } | |||
| 164 | + | ||||
| 160 | devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) | 165 | devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) | ||
| 161 | if err != nil { | 166 | if err != nil { | ||
| 162 | return fmt.Errorf("opening %s: %w", os.DevNull, err) | 167 | return fmt.Errorf("opening %s: %w", os.DevNull, err) | ||
| 163 | } | 168 | } | ||
| 164 | defer func() { _ = devNull.Close() }() | 169 | defer func() { _ = devNull.Close() }() | ||
| 165 | 170 | ||||
| 166 | - | cmd := exec.Command("/proc/self/exe", "--daemon") | 171 | + | cmd := exec.Command(exePath, "--daemon") |
| 167 | cmd.Dir = platform.DirOrHome("") | 172 | cmd.Dir = platform.DirOrHome("") | ||
| 168 | cmd.Stdin = devNull | 173 | cmd.Stdin = devNull | ||
| 169 | cmd.Stdout = devNull | 174 | cmd.Stdout = devNull | ||