From 1cd0846dc92fdcf43ea25bf0013e2681d0b7903d Mon Sep 17 00:00:00 2001 From: Ophestra Umiker Date: Mon, 15 Jul 2024 22:56:50 +0900 Subject: [PATCH] launcher: implement launcher wrapper There is no way to have machinectl pass part of its argv to the child, and formatting the string for a shell is highly error-prone and complex, so the argv slice is encoded and passed to a launcher process launched by machinectl which then calls execve(2) to start the final process. Signed-off-by: Ophestra Umiker --- launcher.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 launcher.go diff --git a/launcher.go b/launcher.go new file mode 100644 index 0000000..68d2cb8 --- /dev/null +++ b/launcher.go @@ -0,0 +1,72 @@ +package main + +import ( + "bytes" + "encoding/base64" + "encoding/gob" + "fmt" + "os" + "strings" + "syscall" +) + +const ( + // hidden path for main to act as a launcher + egoLauncher = "EGO_LAUNCHER" +) + +// hidden launcher path +func tryLauncher() { + if printVersion { + if r, ok := os.LookupEnv(egoLauncher); ok { + // egoLauncher variable contains launcher payload + dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(r)) + + var argv []string + if err := gob.NewDecoder(dec).Decode(&argv); err != nil { + fmt.Println("Error decoding launcher payload:", err) + os.Exit(1) + } + + if err := os.Unsetenv(egoLauncher); err != nil { + fmt.Println("Error unsetting launcher payload:", err) + // not fatal, do not fail + } + + var p string + + if len(argv) > 0 { + if p, ok = which(argv[0]); !ok { + fmt.Printf("Did not find '%s' in PATH\n", argv[0]) + os.Exit(1) + } + } else { + if p, ok = os.LookupEnv("SHELL"); !ok { + fmt.Println("No command was specified and $SHELL was unset") + os.Exit(1) + } + } + + if err := syscall.Exec(p, argv, os.Environ()); err != nil { + fmt.Println("Error executing launcher payload:", err) + os.Exit(1) + } + + // unreachable + os.Exit(1) + return + } + } +} + +func launcherPayloadEnv() string { + r := &bytes.Buffer{} + enc := base64.NewEncoder(base64.StdEncoding, r) + + if err := gob.NewEncoder(enc).Encode(command); err != nil { + fatal("Error encoding launcher payload:", err) + } + + _ = enc.Close() + return egoLauncher + "=" + r.String() +}