hakurei/ldd/exec.go
Ophestra 335a06e476
Some checks failed
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 2m29s
Test / Hakurei (push) Failing after 3m12s
Test / Hpkg (push) Successful in 4m7s
Test / Sandbox (race detector) (push) Successful in 4m19s
Test / Hakurei (race detector) (push) Successful in 5m5s
Test / Flake checks (push) Has been skipped
ldd: decode from reader
The exec function still needs to be migrated to Decoder to benefit from this.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-11-14 08:14:46 +09:00

74 lines
1.7 KiB
Go

package ldd
import (
"bytes"
"context"
"io"
"os"
"os/exec"
"time"
"hakurei.app/container"
"hakurei.app/container/check"
"hakurei.app/container/fhs"
"hakurei.app/container/seccomp"
"hakurei.app/container/std"
"hakurei.app/message"
)
const (
// msgStatic is printed by musl on a statically linked program.
msgStatic = "Not a valid dynamic program"
// msgStaticGlibc is printed by glibc on a statically linked program.
msgStaticGlibc = "not a dynamic executable"
)
// Exec runs ldd(1) in a restrictive [container] and connects it to a [Decoder], returning resulting entries.
func Exec(ctx context.Context, msg message.Msg, p string) ([]*Entry, error) {
const (
lddName = "ldd"
lddTimeout = 4 * time.Second
)
c, cancel := context.WithTimeout(ctx, lddTimeout)
defer cancel()
var toolPath *check.Absolute
if s, err := exec.LookPath(lddName); err != nil {
return nil, err
} else if toolPath, err = check.NewAbs(s); err != nil {
return nil, err
}
z := container.NewCommand(c, msg, toolPath, lddName, p)
z.Hostname = "hakurei-" + lddName
z.SeccompFlags |= seccomp.AllowMultiarch
z.SeccompPresets |= std.PresetStrict
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
z.Stdout = stdout
z.Stderr = stderr
z.
Bind(fhs.AbsRoot, fhs.AbsRoot, 0).
Proc(fhs.AbsProc).
Dev(fhs.AbsDev, false)
if err := z.Start(); err != nil {
return nil, err
}
defer func() { _, _ = io.Copy(os.Stderr, stderr) }()
if err := z.Serve(); err != nil {
return nil, err
}
if err := z.Wait(); err != nil {
m := stderr.Bytes()
if bytes.Contains(m, append([]byte(p+": "), msgStatic...)) ||
bytes.Contains(m, []byte(msgStaticGlibc)) {
return nil, nil
}
return nil, err
}
v := stdout.Bytes()
return Parse(v)
}