diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-07-15 22:56:50 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-07-15 22:56:50 +0900 |
| commit | 1cd0846dc92fdcf43ea25bf0013e2681d0b7903d (patch) | |
| tree | 438981ea9a2f24a6a429437365c02820fd517ed3 /launcher.go | |
| parent | 0bd452ad9b773dd389ef9a858d8d48b922bf5ec6 (diff) | |
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 <cat@ophivana.moe>
Diffstat (limited to 'launcher.go')
| -rw-r--r-- | launcher.go | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/launcher.go b/launcher.go new file mode 100644 index 00000000..68d2cb80 --- /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() +} |
