diff options
| author | James O'Doherty <james@theodohertyfamily.com> | 2026-05-22 11:37:57 -0400 |
|---|---|---|
| committer | James O'Doherty <james@theodohertyfamily.com> | 2026-05-22 11:37:57 -0400 |
| commit | e5bbb969a15c569cf7d37634234a71783f628390 (patch) | |
| tree | 546f8282f14be7d3db1050f1f7586ad3c3758143 /internal | |
| parent | 079e4240534cbdc8751f1a127def20f2d1e58da6 (diff) | |
Fix PID lifecycle race and improve CLI routing for diagnostic commands
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/cli/cli.go | 75 | ||||
| -rw-r--r-- | internal/namespace/launcher_src/launcher.c | 9 |
2 files changed, 73 insertions, 11 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go index aa4268a..13a4a6b 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -21,7 +21,7 @@ func NewApp(args []string) *App { return &App{Args: args} } -func (a *App) Run() error { +func (a *App) Route() error { // 1. Validate arguments for null bytes to prevent exec failures in the C launcher for i, arg := range a.Args { for j := 0; j < len(arg); j++ { @@ -31,10 +31,34 @@ func (a *App) Run() error { } } - // Handle the internal diagnostic commands first + // Handle the internal diagnostic commands that should run on the HOST + if len(a.Args) > 1 { + switch a.Args[1] { + case "show-config": + return a.showConfig() + } + } + + // Handle subcommands first (profile list, import, configure, delete, stop) + if len(a.Args) > 1 && a.Args[1] == "profile" { + return a.handleProfileCmd() + } + + // If we reach here, we are either wrapping a process or running a command + // that requires isolation (e.g., test-ns, test-args). + return a.Run() +} + +func (a *App) Run() error { + // Handle the internal diagnostic commands that require ISOLATION if len(a.Args) > 1 { switch a.Args[1] { case "test-ns": + if !namespace.IsIsolated() { + if err := namespace.Bootstrap(); err != nil { + return fmt.Errorf("bootstrap failed: %w", err) + } + } ok, msg := namespace.VerifyIsolation() if !ok { return fmt.Errorf("isolation check failed: %s", msg) @@ -42,16 +66,15 @@ func (a *App) Run() error { fmt.Println("Isolation Verified: OK") return nil case "test-args": + if !namespace.IsIsolated() { + if err := namespace.Bootstrap(); err != nil { + return fmt.Errorf("bootstrap failed: %w", err) + } + } return namespace.VerifyArguments(a.Args) } } - // Handle subcommands first (profile list, import, configure, delete, stop) - if len(a.Args) > 1 && a.Args[1] == "profile" { - return a.handleProfileCmd() - } - // ... - cfg := &config.Config{} fs := flag.NewFlagSet("wg-wrap", flag.ExitOnError) @@ -194,3 +217,39 @@ func (a *App) handleProfileCmd() error { return fmt.Errorf("unknown profile subcommand: %s", subCmd) } } + +func (a *App) showConfig() error { + cfg := &config.Config{} + fs := flag.NewFlagSet("wg-wrap", flag.ExitOnError) + fs.StringVar(&cfg.Profile, "profile", "default", "WireGuard profile to use") + fs.StringVar(&cfg.DNSServer, "dns-server", "", "Override DNS server to use") + + // Parse the arguments that follow 'show-config' + if len(a.Args) > 2 { + _ = fs.Parse(a.Args[2:]) + } + + // Determine runtime base directory + runtimeBase := a.RuntimeBaseDir + if runtimeBase == "" { + runtimeBase = os.Getenv("XDG_RUNTIME_DIR") + if runtimeBase == "" { + runtimeBase = fmt.Sprintf("/run/user/%d", os.Getuid()) + } + } + + // Resolve paths + profilePath := namespace.GetProfileNamespacePath(runtimeBase, cfg.Profile) + pidsPath := namespace.GetPidsDirPath(runtimeBase, cfg.Profile) + + fmt.Printf("Configuration:\n") + fmt.Printf(" Profile: %s\n", cfg.Profile) + fmt.Printf(" DNS Server: %s\n", cfg.DNSServer) + fmt.Printf(" Runtime Base: %s\n", runtimeBase) + fmt.Printf(" Profile Path: %s\n", profilePath) + fmt.Printf(" PIDs Path: %s\n", pidsPath) + fmt.Printf(" Isolated: %v\n", namespace.IsIsolated()) + fmt.Printf(" UID: %d\n", os.Getuid()) + + return nil +} diff --git a/internal/namespace/launcher_src/launcher.c b/internal/namespace/launcher_src/launcher.c index 63dd6ff..4311430 100644 --- a/internal/namespace/launcher_src/launcher.c +++ b/internal/namespace/launcher_src/launcher.c @@ -65,12 +65,15 @@ int main(int argc, char **argv) { // as the first element of the argv array. // Therefore, argv[0] is the path to the binary we want to execute. if (argv[0] == NULL) { - fprintf(stderr, "No target binary provided in argv[0]\n"); + fprintf(stderr, "No target binary provided in argv[0]\\n"); return 1; } - // Use execv instead of execvp to avoid PATH search issues - // since we are providing an absolute path from Go. + // Prepare a new argv for the target command. + // We want the target binary to see itself as argv[0]. + // The current argv is [target_binary, arg1, arg2, ...]. + // execv expects argv[0] to be the filename, and the rest as arguments. + // This is already the case here, but let's be explicit. if (execv(argv[0], argv) == -1) { perror("execv failed"); return 1; |
