diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-11-12 23:12:38 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-11-12 23:16:13 +0900 |
| commit | f347d44c2281f507e3786aa498f634bfa4c92d84 (patch) | |
| tree | fe85b41d5f6a5e308b87585f46efd64f90221e2b /internal/helper/stub.go | |
| parent | b5630f6883c874d458d9ae3c666cfb7ae5e3121d (diff) | |
internal/helper: relocate from helper
This package is ugly and is pending removal only kept alive by xdg-dbus-proxy.
Its exported symbols are made available until v0.4.0 where it will be removed for #24.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/helper/stub.go')
| -rw-r--r-- | internal/helper/stub.go | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/internal/helper/stub.go b/internal/helper/stub.go new file mode 100644 index 00000000..c1f97e63 --- /dev/null +++ b/internal/helper/stub.go @@ -0,0 +1,102 @@ +package helper + +import ( + "flag" + "fmt" + "io" + "os" + "strconv" + "syscall" +) + +// InternalHelperStub is an internal function but exported because it is cross-package; +// it is part of the implementation of the helper stub. +func InternalHelperStub() { + // this test mocks the helper process + var ap, sp string + if v, ok := os.LookupEnv(HakureiHelper); !ok { + return + } else { + ap = v + } + if v, ok := os.LookupEnv(HakureiStatus); !ok { + panic(HakureiStatus) + } else { + sp = v + } + + genericStub(flagRestoreFiles(1, ap, sp)) + + os.Exit(0) +} + +func newFile(fd int, name, p string) *os.File { + present := false + switch p { + case "0": + case "1": + present = true + default: + panic(fmt.Sprintf("%s fd has unexpected presence value %q", name, p)) + } + + f := os.NewFile(uintptr(fd), name) + if !present && f != nil { + panic(fmt.Sprintf("%s fd set but not present", name)) + } + if present && f == nil { + panic(fmt.Sprintf("%s fd preset but unset", name)) + } + + return f +} + +func flagRestoreFiles(offset int, ap, sp string) (argsFile, statFile *os.File) { + argsFd := flag.Int("args", -1, "") + statFd := flag.Int("fd", -1, "") + _ = flag.CommandLine.Parse(os.Args[offset:]) + argsFile = newFile(*argsFd, "args", ap) + statFile = newFile(*statFd, "stat", sp) + return +} + +func genericStub(argsFile, statFile *os.File) { + if argsFile != nil { + // this output is checked by parent + if _, err := io.Copy(os.Stdout, argsFile); err != nil { + panic("cannot read args: " + err.Error()) + } + } + + if statFile != nil { + // simulate status pipe behaviour + var epoll int + if fd, err := syscall.EpollCreate1(0); err != nil { + panic("cannot open epoll fd: " + err.Error()) + } else { + defer func() { + if err = syscall.Close(fd); err != nil { + panic("cannot close epoll fd: " + err.Error()) + } + }() + epoll = fd + } + if err := syscall.EpollCtl(epoll, syscall.EPOLL_CTL_ADD, int(statFile.Fd()), &syscall.EpollEvent{}); err != nil { + panic("cannot add status pipe to epoll: " + err.Error()) + } + + if _, err := statFile.Write([]byte{'x'}); err != nil { + panic("cannot write to status pipe: " + err.Error()) + } + + // wait for status pipe close + events := make([]syscall.EpollEvent, 1) + if _, err := syscall.EpollWait(epoll, events, -1); err != nil { + panic("cannot poll status pipe: " + err.Error()) + } + if events[0].Events != syscall.EPOLLERR { + panic(strconv.Itoa(int(events[0].Events))) + + } + } +} |
