Compare commits
17 Commits
v0.3.7
...
pkgserver-
| Author | SHA1 | Date | |
|---|---|---|---|
| 33e11856c6 | |||
| 0f944f7a0e | |||
| 223037e7c2 | |||
| acecad7f75 | |||
| 4f82f28c73 | |||
| ae07e0127b | |||
| d2696a6f30 | |||
| 17ba70771c | |||
| 93984f29da | |||
| d7cd746b43 | |||
| b255f07b0f | |||
| dec4cdd068 | |||
| 73c620ecd5 | |||
| 69467a1542 | |||
| 1ae6a35bc8 | |||
| 9ef5b52b85 | |||
| f93158cb3c |
10
README.md
10
README.md
@@ -1,5 +1,5 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://git.gensokyo.uk/rosa/hakurei">
|
<a href="https://git.gensokyo.uk/security/hakurei">
|
||||||
<picture>
|
<picture>
|
||||||
<img src="https://basement.gensokyo.uk/images/yukari1.png" width="200px" alt="Yukari">
|
<img src="https://basement.gensokyo.uk/images/yukari1.png" width="200px" alt="Yukari">
|
||||||
</picture>
|
</picture>
|
||||||
@@ -8,16 +8,16 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://pkg.go.dev/hakurei.app"><img src="https://pkg.go.dev/badge/hakurei.app.svg" alt="Go Reference" /></a>
|
<a href="https://pkg.go.dev/hakurei.app"><img src="https://pkg.go.dev/badge/hakurei.app.svg" alt="Go Reference" /></a>
|
||||||
<a href="https://git.gensokyo.uk/rosa/hakurei/actions"><img src="https://git.gensokyo.uk/rosa/hakurei/actions/workflows/test.yml/badge.svg?branch=staging&style=flat-square" alt="Gitea Workflow Status" /></a>
|
<a href="https://git.gensokyo.uk/security/hakurei/actions"><img src="https://git.gensokyo.uk/security/hakurei/actions/workflows/test.yml/badge.svg?branch=staging&style=flat-square" alt="Gitea Workflow Status" /></a>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://git.gensokyo.uk/rosa/hakurei/releases"><img src="https://img.shields.io/gitea/v/release/rosa/hakurei?gitea_url=https%3A%2F%2Fgit.gensokyo.uk&color=purple" alt="Release" /></a>
|
<a href="https://git.gensokyo.uk/security/hakurei/releases"><img src="https://img.shields.io/gitea/v/release/security/hakurei?gitea_url=https%3A%2F%2Fgit.gensokyo.uk&color=purple" alt="Release" /></a>
|
||||||
<a href="https://goreportcard.com/report/hakurei.app"><img src="https://goreportcard.com/badge/hakurei.app" alt="Go Report Card" /></a>
|
<a href="https://goreportcard.com/report/hakurei.app"><img src="https://goreportcard.com/badge/hakurei.app" alt="Go Report Card" /></a>
|
||||||
<a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
|
<a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Hakurei is a tool for running sandboxed desktop applications as dedicated
|
Hakurei is a tool for running sandboxed desktop applications as dedicated
|
||||||
subordinate users on the Linux kernel. It implements the application container
|
subordinate users on the Linux kernel. It implements the application container
|
||||||
of [planterette (WIP)](https://git.gensokyo.uk/rosa/planterette), a
|
of [planterette (WIP)](https://git.gensokyo.uk/security/planterette), a
|
||||||
self-contained Android-like package manager with modern security features.
|
self-contained Android-like package manager with modern security features.
|
||||||
|
|
||||||
Interaction with hakurei happens entirely through structures described by
|
Interaction with hakurei happens entirely through structures described by
|
||||||
@@ -62,4 +62,4 @@ are very likely to be rejected.
|
|||||||
## NixOS Module (deprecated)
|
## NixOS Module (deprecated)
|
||||||
|
|
||||||
The NixOS module is in maintenance mode and will be removed once planterette is
|
The NixOS module is in maintenance mode and will be removed once planterette is
|
||||||
feature-complete. Full module documentation can be found [here](options.md).
|
feature-complete. Full module documentation can be found [here](options.md).
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
. "syscall"
|
. "syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,22 +12,6 @@ func main() {
|
|||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
log.SetPrefix("earlyinit: ")
|
log.SetPrefix("earlyinit: ")
|
||||||
|
|
||||||
var (
|
|
||||||
option map[string]string
|
|
||||||
flags []string
|
|
||||||
)
|
|
||||||
if len(os.Args) > 1 {
|
|
||||||
option = make(map[string]string)
|
|
||||||
for _, s := range os.Args[1:] {
|
|
||||||
key, value, ok := strings.Cut(s, "=")
|
|
||||||
if !ok {
|
|
||||||
flags = append(flags, s)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
option[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := Mount(
|
if err := Mount(
|
||||||
"devtmpfs",
|
"devtmpfs",
|
||||||
"/dev/",
|
"/dev/",
|
||||||
@@ -72,56 +55,4 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// staying in rootfs, these are no longer used
|
|
||||||
must(os.Remove("/root"))
|
|
||||||
must(os.Remove("/init"))
|
|
||||||
|
|
||||||
must(os.Mkdir("/proc", 0))
|
|
||||||
mustSyscall("mount proc", Mount(
|
|
||||||
"proc",
|
|
||||||
"/proc",
|
|
||||||
"proc",
|
|
||||||
MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
|
||||||
"hidepid=1",
|
|
||||||
))
|
|
||||||
|
|
||||||
must(os.Mkdir("/sys", 0))
|
|
||||||
mustSyscall("mount sysfs", Mount(
|
|
||||||
"sysfs",
|
|
||||||
"/sys",
|
|
||||||
"sysfs",
|
|
||||||
0,
|
|
||||||
"",
|
|
||||||
))
|
|
||||||
|
|
||||||
// after top level has been set up
|
|
||||||
mustSyscall("remount root", Mount(
|
|
||||||
"",
|
|
||||||
"/",
|
|
||||||
"",
|
|
||||||
MS_REMOUNT|MS_BIND|
|
|
||||||
MS_RDONLY|MS_NODEV|MS_NOSUID|MS_NOEXEC,
|
|
||||||
"",
|
|
||||||
))
|
|
||||||
|
|
||||||
must(os.WriteFile(
|
|
||||||
"/sys/module/firmware_class/parameters/path",
|
|
||||||
[]byte("/system/lib/firmware"),
|
|
||||||
0,
|
|
||||||
))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// mustSyscall calls [log.Fatalln] if err is non-nil.
|
|
||||||
func mustSyscall(action string, err error) {
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("cannot "+action+":", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// must calls [log.Fatal] with err if it is non-nil.
|
|
||||||
func must(err error) {
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"hakurei.app/command"
|
"hakurei.app/command"
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
"hakurei.app/container/std"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal/dbus"
|
"hakurei.app/internal/dbus"
|
||||||
"hakurei.app/internal/env"
|
"hakurei.app/internal/env"
|
||||||
@@ -90,9 +89,6 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
flagHomeDir string
|
flagHomeDir string
|
||||||
flagUserName string
|
flagUserName string
|
||||||
|
|
||||||
flagSchedPolicy string
|
|
||||||
flagSchedPriority int
|
|
||||||
|
|
||||||
flagPrivateRuntime, flagPrivateTmpdir bool
|
flagPrivateRuntime, flagPrivateTmpdir bool
|
||||||
|
|
||||||
flagWayland, flagX11, flagDBus, flagPipeWire, flagPulse bool
|
flagWayland, flagX11, flagDBus, flagPipeWire, flagPulse bool
|
||||||
@@ -135,7 +131,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
log.Fatal(optionalErrorUnwrap(err))
|
log.Fatal(optionalErrorUnwrap(err))
|
||||||
return err
|
return err
|
||||||
} else if progPath, err = check.NewAbs(p); err != nil {
|
} else if progPath, err = check.NewAbs(p); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,7 +150,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
et |= hst.EPipeWire
|
et |= hst.EPipeWire
|
||||||
}
|
}
|
||||||
|
|
||||||
config := hst.Config{
|
config := &hst.Config{
|
||||||
ID: flagID,
|
ID: flagID,
|
||||||
Identity: flagIdentity,
|
Identity: flagIdentity,
|
||||||
Groups: flagGroups,
|
Groups: flagGroups,
|
||||||
@@ -181,13 +177,6 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.SchedPolicy.UnmarshalText(
|
|
||||||
[]byte(flagSchedPolicy),
|
|
||||||
); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
config.SchedPriority = std.Int(flagSchedPriority)
|
|
||||||
|
|
||||||
// bind GPU stuff
|
// bind GPU stuff
|
||||||
if et&(hst.EX11|hst.EWayland) != 0 {
|
if et&(hst.EX11|hst.EWayland) != 0 {
|
||||||
config.Container.Filesystem = append(config.Container.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
|
config.Container.Filesystem = append(config.Container.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
|
||||||
@@ -225,7 +214,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
homeDir = passwd.HomeDir
|
homeDir = passwd.HomeDir
|
||||||
}
|
}
|
||||||
if a, err := check.NewAbs(homeDir); err != nil {
|
if a, err := check.NewAbs(homeDir); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
config.Container.Home = a
|
config.Container.Home = a
|
||||||
@@ -245,11 +234,11 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
config.SessionBus = dbus.NewConfig(flagID, true, flagDBusMpris)
|
config.SessionBus = dbus.NewConfig(flagID, true, flagDBusMpris)
|
||||||
} else {
|
} else {
|
||||||
if f, err := os.Open(flagDBusConfigSession); err != nil {
|
if f, err := os.Open(flagDBusConfigSession); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
} else {
|
} else {
|
||||||
decodeJSON(log.Fatal, "load session bus proxy config", f, &config.SessionBus)
|
decodeJSON(log.Fatal, "load session bus proxy config", f, &config.SessionBus)
|
||||||
if err = f.Close(); err != nil {
|
if err = f.Close(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,11 +246,11 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
// system bus proxy is optional
|
// system bus proxy is optional
|
||||||
if flagDBusConfigSystem != "nil" {
|
if flagDBusConfigSystem != "nil" {
|
||||||
if f, err := os.Open(flagDBusConfigSystem); err != nil {
|
if f, err := os.Open(flagDBusConfigSystem); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
} else {
|
} else {
|
||||||
decodeJSON(log.Fatal, "load system bus proxy config", f, &config.SystemBus)
|
decodeJSON(log.Fatal, "load system bus proxy config", f, &config.SystemBus)
|
||||||
if err = f.Close(); err != nil {
|
if err = f.Close(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +266,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outcome.Main(ctx, msg, &config, -1)
|
outcome.Main(ctx, msg, config, -1)
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}).
|
}).
|
||||||
Flag(&flagDBusConfigSession, "dbus-config", command.StringFlag("builtin"),
|
Flag(&flagDBusConfigSession, "dbus-config", command.StringFlag("builtin"),
|
||||||
@@ -298,10 +287,6 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
"Container home directory").
|
"Container home directory").
|
||||||
Flag(&flagUserName, "u", command.StringFlag("chronos"),
|
Flag(&flagUserName, "u", command.StringFlag("chronos"),
|
||||||
"Passwd user name within sandbox").
|
"Passwd user name within sandbox").
|
||||||
Flag(&flagSchedPolicy, "policy", command.StringFlag(""),
|
|
||||||
"Scheduling policy to set for the container").
|
|
||||||
Flag(&flagSchedPriority, "priority", command.IntFlag(0),
|
|
||||||
"Scheduling priority to set for the container").
|
|
||||||
Flag(&flagPrivateRuntime, "private-runtime", command.BoolFlag(false),
|
Flag(&flagPrivateRuntime, "private-runtime", command.BoolFlag(false),
|
||||||
"Do not share XDG_RUNTIME_DIR between containers under the same identity").
|
"Do not share XDG_RUNTIME_DIR between containers under the same identity").
|
||||||
Flag(&flagPrivateTmpdir, "private-tmpdir", command.BoolFlag(false),
|
Flag(&flagPrivateTmpdir, "private-tmpdir", command.BoolFlag(false),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Commands:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"run", []string{"run", "-h"}, `
|
"run", []string{"run", "-h"}, `
|
||||||
Usage: hakurei run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--policy <value>] [--priority <int>] [--private-runtime] [--private-tmpdir] [--wayland] [-X] [--dbus] [--pipewire] [--pulse] COMMAND [OPTIONS]
|
Usage: hakurei run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--private-runtime] [--private-tmpdir] [--wayland] [-X] [--dbus] [--pipewire] [--pulse] COMMAND [OPTIONS]
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-X Enable direct connection to X11
|
-X Enable direct connection to X11
|
||||||
@@ -60,10 +60,6 @@ Flags:
|
|||||||
Allow owning MPRIS D-Bus path, has no effect if custom config is available
|
Allow owning MPRIS D-Bus path, has no effect if custom config is available
|
||||||
-pipewire
|
-pipewire
|
||||||
Enable connection to PipeWire via SecurityContext
|
Enable connection to PipeWire via SecurityContext
|
||||||
-policy string
|
|
||||||
Scheduling policy to set for the container
|
|
||||||
-priority int
|
|
||||||
Scheduling priority to set for the container
|
|
||||||
-private-runtime
|
-private-runtime
|
||||||
Do not share XDG_RUNTIME_DIR between containers under the same identity
|
Do not share XDG_RUNTIME_DIR between containers under the same identity
|
||||||
-private-tmpdir
|
-private-tmpdir
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if flagIdle {
|
if flagIdle {
|
||||||
pkg.SetSchedIdle = true
|
pkg.SchedPolicy = container.SCHED_IDLE
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -175,17 +175,6 @@ func main() {
|
|||||||
fmt.Println("website : " +
|
fmt.Println("website : " +
|
||||||
strings.TrimSuffix(meta.Website, "/"))
|
strings.TrimSuffix(meta.Website, "/"))
|
||||||
}
|
}
|
||||||
if len(meta.Dependencies) > 0 {
|
|
||||||
fmt.Print("depends on :")
|
|
||||||
for _, d := range meta.Dependencies {
|
|
||||||
s := rosa.GetMetadata(d).Name
|
|
||||||
if version := rosa.Std.Version(d); version != rosa.Unversioned {
|
|
||||||
s += "-" + version
|
|
||||||
}
|
|
||||||
fmt.Print(" " + s)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusPrefix = "status : "
|
const statusPrefix = "status : "
|
||||||
if flagStatus {
|
if flagStatus {
|
||||||
@@ -434,8 +423,7 @@ func main() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var (
|
var (
|
||||||
flagDump string
|
flagDump string
|
||||||
flagExport string
|
|
||||||
)
|
)
|
||||||
c.NewCommand(
|
c.NewCommand(
|
||||||
"cure",
|
"cure",
|
||||||
@@ -448,34 +436,10 @@ func main() {
|
|||||||
return fmt.Errorf("unknown artifact %q", args[0])
|
return fmt.Errorf("unknown artifact %q", args[0])
|
||||||
} else if flagDump == "" {
|
} else if flagDump == "" {
|
||||||
pathname, _, err := cache.Cure(rosa.Std.Load(p))
|
pathname, _, err := cache.Cure(rosa.Std.Load(p))
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
log.Println(pathname)
|
||||||
}
|
}
|
||||||
log.Println(pathname)
|
return err
|
||||||
|
|
||||||
if flagExport != "" {
|
|
||||||
msg.Verbosef("exporting %s to %s...", args[0], flagExport)
|
|
||||||
|
|
||||||
var f *os.File
|
|
||||||
if f, err = os.OpenFile(
|
|
||||||
flagExport,
|
|
||||||
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
|
|
||||||
0400,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _, err = pkg.Flatten(
|
|
||||||
os.DirFS(pathname.String()),
|
|
||||||
".",
|
|
||||||
f,
|
|
||||||
); err != nil {
|
|
||||||
_ = f.Close()
|
|
||||||
return err
|
|
||||||
} else if err = f.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
} else {
|
} else {
|
||||||
f, err := os.OpenFile(
|
f, err := os.OpenFile(
|
||||||
flagDump,
|
flagDump,
|
||||||
@@ -499,11 +463,6 @@ func main() {
|
|||||||
&flagDump,
|
&flagDump,
|
||||||
"dump", command.StringFlag(""),
|
"dump", command.StringFlag(""),
|
||||||
"Write IR to specified pathname and terminate",
|
"Write IR to specified pathname and terminate",
|
||||||
).
|
|
||||||
Flag(
|
|
||||||
&flagExport,
|
|
||||||
"export", command.StringFlag(""),
|
|
||||||
"Export cured artifact to specified pathname",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,19 +477,17 @@ func main() {
|
|||||||
"shell",
|
"shell",
|
||||||
"Interactive shell in the specified Rosa OS environment",
|
"Interactive shell in the specified Rosa OS environment",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
presets := make([]rosa.PArtifact, len(args))
|
root := make([]pkg.Artifact, 0, 6+len(args))
|
||||||
for i, arg := range args {
|
for _, arg := range args {
|
||||||
p, ok := rosa.ResolveName(arg)
|
p, ok := rosa.ResolveName(arg)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown artifact %q", arg)
|
return fmt.Errorf("unknown artifact %q", arg)
|
||||||
}
|
}
|
||||||
presets[i] = p
|
root = append(root, rosa.Std.Load(p))
|
||||||
}
|
}
|
||||||
root := make(rosa.Collect, 0, 6+len(args))
|
|
||||||
root = rosa.Std.AppendPresets(root, presets...)
|
|
||||||
|
|
||||||
if flagWithToolchain {
|
if flagWithToolchain {
|
||||||
musl, compilerRT, runtimes, clang := (rosa.Std - 1).NewLLVM()
|
musl, compilerRT, runtimes, clang := rosa.Std.NewLLVM()
|
||||||
root = append(root, musl, compilerRT, runtimes, clang)
|
root = append(root, musl, compilerRT, runtimes, clang)
|
||||||
} else {
|
} else {
|
||||||
root = append(root, rosa.Std.Load(rosa.Musl))
|
root = append(root, rosa.Std.Load(rosa.Musl))
|
||||||
@@ -540,12 +497,6 @@ func main() {
|
|||||||
rosa.Std.Load(rosa.Toybox),
|
rosa.Std.Load(rosa.Toybox),
|
||||||
)
|
)
|
||||||
|
|
||||||
if _, _, err := cache.Cure(&root); err == nil {
|
|
||||||
return errors.New("unreachable")
|
|
||||||
} else if !errors.Is(err, rosa.Collected{}) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type cureRes struct {
|
type cureRes struct {
|
||||||
pathname *check.Absolute
|
pathname *check.Absolute
|
||||||
checksum unique.Handle[pkg.Checksum]
|
checksum unique.Handle[pkg.Checksum]
|
||||||
|
|||||||
229
cmd/pkgserver/main.go
Normal file
229
cmd/pkgserver/main.go
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"cmp"
|
||||||
|
"context"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"hakurei.app/command"
|
||||||
|
"hakurei.app/container/check"
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
"hakurei.app/internal/rosa"
|
||||||
|
"hakurei.app/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate sh -c "sass ui/static/dark.scss ui/static/dark.css && sass ui/static/light.scss ui/static/light.css && tsc ui/static/index.ts"
|
||||||
|
//go:embed ui/*
|
||||||
|
var content embed.FS
|
||||||
|
|
||||||
|
func serveWebUI(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Printf("serveWebUI: %s\n", r.URL.Path)
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
w.Header().Set("Expires", "0")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("X-XSS-Protection", "1")
|
||||||
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
|
|
||||||
|
http.ServeFileFS(w, r, content, "ui/index.html")
|
||||||
|
}
|
||||||
|
func serveStaticContent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Printf("serveStaticContent: %s\n", r.URL.Path)
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/static/style.css":
|
||||||
|
darkTheme := r.CookiesNamed("dark_theme")
|
||||||
|
if len(darkTheme) > 0 && darkTheme[0].Value == "true" {
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/dark.css")
|
||||||
|
} else {
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/light.css")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "/favicon.ico":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/favicon.ico")
|
||||||
|
break
|
||||||
|
case "/static/index.js":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/index.js")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func serveAPI(index *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveStatus(index *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if index == nil {
|
||||||
|
http.Error(w, "index is nil", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
base := path.Base(r.URL.Path)
|
||||||
|
name := strings.TrimSuffix(base, ".log")
|
||||||
|
p, ok := rosa.ResolveName(name)
|
||||||
|
if !ok {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := rosa.GetMetadata(p)
|
||||||
|
pk, ok := index.names[m.Name]
|
||||||
|
if !ok {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(pk.status) > 0 {
|
||||||
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, err := io.Copy(w, bytes.NewReader(pk.status))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SortOrders int
|
||||||
|
|
||||||
|
const (
|
||||||
|
DeclarationAscending SortOrders = iota
|
||||||
|
DeclarationDescending
|
||||||
|
NameAscending
|
||||||
|
NameDescending
|
||||||
|
limitSortOrders
|
||||||
|
)
|
||||||
|
|
||||||
|
type PackageIndex struct {
|
||||||
|
sorts [limitSortOrders][rosa.PresetUnexportedStart]*PackageIndexEntry
|
||||||
|
names map[string]*PackageIndexEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
type PackageIndexEntry struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Website string `json:"website"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
status []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPackageIndex(cache *pkg.Cache, report *rosa.Report) (_ *PackageIndex, err error) {
|
||||||
|
index := new(PackageIndex)
|
||||||
|
index.names = make(map[string]*PackageIndexEntry, rosa.PresetUnexportedStart)
|
||||||
|
work := make([]PackageIndexEntry, rosa.PresetUnexportedStart)
|
||||||
|
defer report.HandleAccess(&err)()
|
||||||
|
for p := range rosa.PresetUnexportedStart {
|
||||||
|
m := rosa.GetMetadata(p)
|
||||||
|
v := rosa.Std.Version(p)
|
||||||
|
a := rosa.Std.Load(p)
|
||||||
|
id := cache.Ident(a)
|
||||||
|
st, n := report.ArtifactOf(id)
|
||||||
|
var status []byte
|
||||||
|
if n < 1 {
|
||||||
|
status = nil
|
||||||
|
} else {
|
||||||
|
status = st
|
||||||
|
}
|
||||||
|
log.Printf("Processing package %s...\n", m.Name)
|
||||||
|
entry := PackageIndexEntry{
|
||||||
|
Name: m.Name,
|
||||||
|
Description: m.Description,
|
||||||
|
Website: m.Website,
|
||||||
|
Version: v,
|
||||||
|
status: status,
|
||||||
|
}
|
||||||
|
work[p] = entry
|
||||||
|
index.names[m.Name] = &entry
|
||||||
|
}
|
||||||
|
for i, p := range work {
|
||||||
|
index.sorts[DeclarationAscending][i] = &p
|
||||||
|
}
|
||||||
|
slices.Reverse(work)
|
||||||
|
for i, p := range work {
|
||||||
|
index.sorts[DeclarationDescending][i] = &p
|
||||||
|
}
|
||||||
|
slices.SortFunc(work, func(a PackageIndexEntry, b PackageIndexEntry) int {
|
||||||
|
return cmp.Compare(a.Name, b.Name)
|
||||||
|
})
|
||||||
|
for i, p := range work {
|
||||||
|
index.sorts[NameAscending][i] = &p
|
||||||
|
}
|
||||||
|
slices.Reverse(work)
|
||||||
|
for i, p := range work {
|
||||||
|
index.sorts[NameDescending][i] = &p
|
||||||
|
}
|
||||||
|
return index, err
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("pkgserver: ")
|
||||||
|
|
||||||
|
var (
|
||||||
|
flagBaseDir string
|
||||||
|
flagPort int
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||||
|
defer stop()
|
||||||
|
msg := message.New(log.Default())
|
||||||
|
|
||||||
|
c := command.New(os.Stderr, log.Printf, "pkgserver", func(args []string) error {
|
||||||
|
reportPath := args[0]
|
||||||
|
baseDir, err := check.NewAbs(flagBaseDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Println("baseDir:", baseDir)
|
||||||
|
cache, err := pkg.Open(ctx, msg, 0, baseDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
report, err := rosa.OpenReport(reportPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Println("reportPath:", reportPath)
|
||||||
|
log.Println("indexing packages...")
|
||||||
|
index, err := createPackageIndex(cache, report)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Println("created package index")
|
||||||
|
http.HandleFunc("GET /{$}", serveWebUI)
|
||||||
|
http.HandleFunc("GET /favicon.ico", serveStaticContent)
|
||||||
|
http.HandleFunc("GET /static/", serveStaticContent)
|
||||||
|
http.HandleFunc("GET /api/", serveAPI(index))
|
||||||
|
http.HandleFunc("GET /api/status/", serveStatus(index))
|
||||||
|
log.Println("listening on", flagPort)
|
||||||
|
err = http.ListenAndServe(fmt.Sprintf(":%d", flagPort), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}).Flag(
|
||||||
|
&flagBaseDir,
|
||||||
|
"b", command.StringFlag(""),
|
||||||
|
"base directory for cache",
|
||||||
|
).Flag(
|
||||||
|
&flagPort,
|
||||||
|
"p", command.IntFlag(8067),
|
||||||
|
"http listen port",
|
||||||
|
)
|
||||||
|
c.MustParse(os.Args[1:], func(e error) {
|
||||||
|
log.Fatal(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
26
cmd/pkgserver/ui/index.html
Normal file
26
cmd/pkgserver/ui/index.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="stylesheet" href="static/style.css">
|
||||||
|
<title>Hakurei PkgServer</title>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||||
|
<script src="static/index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hakurei PkgServer</h1>
|
||||||
|
|
||||||
|
<table id="pkg-list">
|
||||||
|
<tr><th>Status</th><th>Name</th><th>Version</th></tr>
|
||||||
|
</table>
|
||||||
|
<p>Showing entries <span id="entry-counter"></span>.</p>
|
||||||
|
<span class="bottom-nav"><a href="javascript:prevPage()">« Previous</a> <span id="page-number">1</span> <a href="javascript:nextPage()">Next »</a></span>
|
||||||
|
<span><label for="count">Entries per page:</label><select name="count" id="count">
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="25">25</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
</select></span>
|
||||||
|
</body>
|
||||||
|
<footer>© <a href="https://hakurei.app/">Hakurei</a>. Licensed under the MIT license.</footer>
|
||||||
|
</html>
|
||||||
0
cmd/pkgserver/ui/static/_common.scss
Normal file
0
cmd/pkgserver/ui/static/_common.scss
Normal file
6
cmd/pkgserver/ui/static/dark.css
Normal file
6
cmd/pkgserver/ui/static/dark.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
html {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
color: ghostwhite; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=dark.css.map */
|
||||||
7
cmd/pkgserver/ui/static/dark.css.map
Normal file
7
cmd/pkgserver/ui/static/dark.css.map
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAAA,aAAa;AAEb,IAAK;EACH,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,UAAU",
|
||||||
|
"sources": ["dark.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "dark.css"
|
||||||
|
}
|
||||||
6
cmd/pkgserver/ui/static/dark.scss
Normal file
6
cmd/pkgserver/ui/static/dark.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
|
||||||
|
html {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
color: ghostwhite;
|
||||||
|
}
|
||||||
BIN
cmd/pkgserver/ui/static/favicon.ico
Normal file
BIN
cmd/pkgserver/ui/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
67
cmd/pkgserver/ui/static/index.js
Normal file
67
cmd/pkgserver/ui/static/index.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"use strict";
|
||||||
|
var PackageEntry = /** @class */ (function () {
|
||||||
|
function PackageEntry() {
|
||||||
|
}
|
||||||
|
return PackageEntry;
|
||||||
|
}());
|
||||||
|
var State = /** @class */ (function () {
|
||||||
|
function State() {
|
||||||
|
this.entriesPerPage = 10;
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.entryIndex = 0;
|
||||||
|
this.loadedEntries = [];
|
||||||
|
}
|
||||||
|
State.prototype.getEntriesPerPage = function () {
|
||||||
|
return this.entriesPerPage;
|
||||||
|
};
|
||||||
|
State.prototype.setEntriesPerPage = function (entriesPerPage) {
|
||||||
|
this.entriesPerPage = entriesPerPage;
|
||||||
|
this.updateRange();
|
||||||
|
};
|
||||||
|
State.prototype.getCurrentPage = function () {
|
||||||
|
return this.currentPage;
|
||||||
|
};
|
||||||
|
State.prototype.setCurrentPage = function (page) {
|
||||||
|
this.currentPage = page;
|
||||||
|
document.getElementById("page-number").innerText = String(this.currentPage);
|
||||||
|
this.updateRange();
|
||||||
|
};
|
||||||
|
State.prototype.getEntryIndex = function () {
|
||||||
|
return this.entryIndex;
|
||||||
|
};
|
||||||
|
State.prototype.setEntryIndex = function (entryIndex) {
|
||||||
|
this.entryIndex = entryIndex;
|
||||||
|
this.updateRange();
|
||||||
|
};
|
||||||
|
State.prototype.getLoadedEntries = function () {
|
||||||
|
return this.loadedEntries;
|
||||||
|
};
|
||||||
|
State.prototype.getMaxPage = function () {
|
||||||
|
return this.loadedEntries.length / this.entriesPerPage;
|
||||||
|
};
|
||||||
|
State.prototype.updateRange = function () {
|
||||||
|
var max = Math.min(this.entryIndex + this.entriesPerPage, this.loadedEntries.length);
|
||||||
|
document.getElementById("entry-counter").innerText = "".concat(this.entryIndex, "-").concat(max, " of ").concat(this.loadedEntries.length);
|
||||||
|
};
|
||||||
|
return State;
|
||||||
|
}());
|
||||||
|
var STATE;
|
||||||
|
function prevPage() {
|
||||||
|
var current = STATE.getCurrentPage();
|
||||||
|
if (current > 1) {
|
||||||
|
STATE.setCurrentPage(STATE.getCurrentPage() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function nextPage() {
|
||||||
|
var current = STATE.getCurrentPage();
|
||||||
|
if (current < STATE.getMaxPage()) {
|
||||||
|
STATE.setCurrentPage(STATE.getCurrentPage() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
STATE = new State();
|
||||||
|
STATE.updateRange();
|
||||||
|
document.getElementById("count").addEventListener("change", function (event) {
|
||||||
|
STATE.setEntriesPerPage(parseInt(event.target.value));
|
||||||
|
});
|
||||||
|
});
|
||||||
66
cmd/pkgserver/ui/static/index.ts
Normal file
66
cmd/pkgserver/ui/static/index.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
class PackageEntry {
|
||||||
|
|
||||||
|
}
|
||||||
|
class State {
|
||||||
|
entriesPerPage: number = 10
|
||||||
|
currentPage: number = 1
|
||||||
|
entryIndex: number = 0
|
||||||
|
loadedEntries: PackageEntry[] = []
|
||||||
|
getEntriesPerPage(): number {
|
||||||
|
return this.entriesPerPage
|
||||||
|
}
|
||||||
|
setEntriesPerPage(entriesPerPage: number) {
|
||||||
|
this.entriesPerPage = entriesPerPage
|
||||||
|
this.updateRange()
|
||||||
|
}
|
||||||
|
getCurrentPage(): number {
|
||||||
|
return this.currentPage
|
||||||
|
}
|
||||||
|
setCurrentPage(page: number) {
|
||||||
|
this.currentPage = page
|
||||||
|
document.getElementById("page-number").innerText = String(this.currentPage)
|
||||||
|
this.updateRange()
|
||||||
|
}
|
||||||
|
getEntryIndex(): number {
|
||||||
|
return this.entryIndex
|
||||||
|
}
|
||||||
|
setEntryIndex(entryIndex: number) {
|
||||||
|
this.entryIndex = entryIndex
|
||||||
|
this.updateRange()
|
||||||
|
}
|
||||||
|
getLoadedEntries(): PackageEntry[] {
|
||||||
|
return this.loadedEntries
|
||||||
|
}
|
||||||
|
getMaxPage(): number {
|
||||||
|
return this.loadedEntries.length / this.entriesPerPage
|
||||||
|
}
|
||||||
|
updateRange() {
|
||||||
|
let max = Math.min(this.entryIndex + this.entriesPerPage, this.loadedEntries.length)
|
||||||
|
document.getElementById("entry-counter").innerText = `${this.entryIndex}-${max} of ${this.loadedEntries.length}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let STATE: State
|
||||||
|
|
||||||
|
function prevPage() {
|
||||||
|
let current = STATE.getCurrentPage()
|
||||||
|
if (current > 1) {
|
||||||
|
STATE.setCurrentPage(STATE.getCurrentPage() - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function nextPage() {
|
||||||
|
let current = STATE.getCurrentPage()
|
||||||
|
if (current < STATE.getMaxPage()) {
|
||||||
|
STATE.setCurrentPage(STATE.getCurrentPage() + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
STATE = new State()
|
||||||
|
STATE.updateRange()
|
||||||
|
document.getElementById("count").addEventListener("change", (event) => {
|
||||||
|
STATE.setEntriesPerPage(parseInt((event.target as HTMLSelectElement).value))
|
||||||
|
})
|
||||||
|
})
|
||||||
6
cmd/pkgserver/ui/static/light.css
Normal file
6
cmd/pkgserver/ui/static/light.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
html {
|
||||||
|
background-color: #d3d3d3;
|
||||||
|
color: black; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=light.css.map */
|
||||||
7
cmd/pkgserver/ui/static/light.css.map
Normal file
7
cmd/pkgserver/ui/static/light.css.map
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAAA,aAAa;AAEb,IAAK;EACH,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,KAAK",
|
||||||
|
"sources": ["light.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "light.css"
|
||||||
|
}
|
||||||
6
cmd/pkgserver/ui/static/light.scss
Normal file
6
cmd/pkgserver/ui/static/light.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
|
||||||
|
html {
|
||||||
|
background-color: #d3d3d3;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
@@ -38,13 +38,9 @@ type (
|
|||||||
Container struct {
|
Container struct {
|
||||||
// Whether the container init should stay alive after its parent terminates.
|
// Whether the container init should stay alive after its parent terminates.
|
||||||
AllowOrphan bool
|
AllowOrphan bool
|
||||||
// Whether to set SchedPolicy and SchedPriority via sched_setscheduler(2).
|
// Scheduling policy to set via sched_setscheduler(2). The zero value
|
||||||
SetScheduler bool
|
// skips this call. Supported policies are [SCHED_BATCH], [SCHED_IDLE].
|
||||||
// Scheduling policy to set via sched_setscheduler(2).
|
SchedPolicy int
|
||||||
SchedPolicy std.SchedPolicy
|
|
||||||
// Scheduling priority to set via sched_setscheduler(2). The zero value
|
|
||||||
// implies the minimum value supported by the current SchedPolicy.
|
|
||||||
SchedPriority std.Int
|
|
||||||
// Cgroup fd, nil to disable.
|
// Cgroup fd, nil to disable.
|
||||||
Cgroup *int
|
Cgroup *int
|
||||||
// ExtraFiles passed through to initial process in the container, with
|
// ExtraFiles passed through to initial process in the container, with
|
||||||
@@ -377,38 +373,16 @@ func (p *Container) Start() error {
|
|||||||
|
|
||||||
// sched_setscheduler: thread-directed but acts on all processes
|
// sched_setscheduler: thread-directed but acts on all processes
|
||||||
// created from the calling thread
|
// created from the calling thread
|
||||||
if p.SetScheduler {
|
if p.SchedPolicy > 0 {
|
||||||
if p.SchedPolicy < 0 || p.SchedPolicy > std.SCHED_LAST {
|
p.msg.Verbosef("setting scheduling policy %d", p.SchedPolicy)
|
||||||
return &StartError{
|
|
||||||
Fatal: false,
|
|
||||||
Step: "set scheduling policy",
|
|
||||||
Err: EINVAL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var param schedParam
|
|
||||||
if priority, err := p.SchedPolicy.GetPriorityMin(); err != nil {
|
|
||||||
return &StartError{
|
|
||||||
Fatal: true,
|
|
||||||
Step: "get minimum priority",
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
param.priority = max(priority, p.SchedPriority)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.msg.Verbosef(
|
|
||||||
"setting scheduling policy %s priority %d",
|
|
||||||
p.SchedPolicy, param.priority,
|
|
||||||
)
|
|
||||||
if err := schedSetscheduler(
|
if err := schedSetscheduler(
|
||||||
0, // calling thread
|
0, // calling thread
|
||||||
p.SchedPolicy,
|
p.SchedPolicy,
|
||||||
¶m,
|
&schedParam{0},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return &StartError{
|
return &StartError{
|
||||||
Fatal: true,
|
Fatal: true,
|
||||||
Step: "set scheduling policy",
|
Step: "enforce landlock ruleset",
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
package std
|
package std
|
||||||
|
|
||||||
import (
|
import "iter"
|
||||||
"encoding"
|
|
||||||
"iter"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Syscalls returns an iterator over all wired syscalls.
|
// Syscalls returns an iterator over all wired syscalls.
|
||||||
func Syscalls() iter.Seq2[string, ScmpSyscall] {
|
func Syscalls() iter.Seq2[string, ScmpSyscall] {
|
||||||
@@ -32,128 +26,3 @@ func SyscallResolveName(name string) (num ScmpSyscall, ok bool) {
|
|||||||
num, ok = syscallNumExtra[name]
|
num, ok = syscallNumExtra[name]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchedPolicy denotes a scheduling policy defined in include/uapi/linux/sched.h.
|
|
||||||
type SchedPolicy int
|
|
||||||
|
|
||||||
// include/uapi/linux/sched.h
|
|
||||||
const (
|
|
||||||
SCHED_NORMAL SchedPolicy = iota
|
|
||||||
SCHED_FIFO
|
|
||||||
SCHED_RR
|
|
||||||
SCHED_BATCH
|
|
||||||
_SCHED_ISO // SCHED_ISO: reserved but not implemented yet
|
|
||||||
SCHED_IDLE
|
|
||||||
SCHED_DEADLINE
|
|
||||||
SCHED_EXT
|
|
||||||
|
|
||||||
SCHED_LAST SchedPolicy = iota - 1
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ encoding.TextMarshaler = SCHED_LAST
|
|
||||||
var _ encoding.TextUnmarshaler = new(SCHED_LAST)
|
|
||||||
|
|
||||||
// String returns a unique representation of policy, also used in encoding.
|
|
||||||
func (policy SchedPolicy) String() string {
|
|
||||||
switch policy {
|
|
||||||
case SCHED_NORMAL:
|
|
||||||
return ""
|
|
||||||
case SCHED_FIFO:
|
|
||||||
return "fifo"
|
|
||||||
case SCHED_RR:
|
|
||||||
return "rr"
|
|
||||||
case SCHED_BATCH:
|
|
||||||
return "batch"
|
|
||||||
case SCHED_IDLE:
|
|
||||||
return "idle"
|
|
||||||
case SCHED_DEADLINE:
|
|
||||||
return "deadline"
|
|
||||||
case SCHED_EXT:
|
|
||||||
return "ext"
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "invalid policy " + strconv.Itoa(int(policy))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalText performs bounds checking and returns the result of String.
|
|
||||||
func (policy SchedPolicy) MarshalText() ([]byte, error) {
|
|
||||||
if policy == _SCHED_ISO || policy < 0 || policy > SCHED_LAST {
|
|
||||||
return nil, syscall.EINVAL
|
|
||||||
}
|
|
||||||
return []byte(policy.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidSchedPolicyError is an invalid string representation of a [SchedPolicy].
|
|
||||||
type InvalidSchedPolicyError string
|
|
||||||
|
|
||||||
func (InvalidSchedPolicyError) Unwrap() error { return syscall.EINVAL }
|
|
||||||
func (e InvalidSchedPolicyError) Error() string {
|
|
||||||
return "invalid scheduling policy " + strconv.Quote(string(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalText is the inverse of MarshalText.
|
|
||||||
func (policy *SchedPolicy) UnmarshalText(text []byte) error {
|
|
||||||
switch string(text) {
|
|
||||||
case "fifo":
|
|
||||||
*policy = SCHED_FIFO
|
|
||||||
case "rr":
|
|
||||||
*policy = SCHED_RR
|
|
||||||
case "batch":
|
|
||||||
*policy = SCHED_BATCH
|
|
||||||
case "idle":
|
|
||||||
*policy = SCHED_IDLE
|
|
||||||
case "deadline":
|
|
||||||
*policy = SCHED_DEADLINE
|
|
||||||
case "ext":
|
|
||||||
*policy = SCHED_EXT
|
|
||||||
|
|
||||||
case "":
|
|
||||||
*policy = 0
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return InvalidSchedPolicyError(text)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// for sched_get_priority_max and sched_get_priority_min
|
|
||||||
var (
|
|
||||||
schedPriority [SCHED_LAST + 1][2]Int
|
|
||||||
schedPriorityErr [SCHED_LAST + 1][2]error
|
|
||||||
schedPriorityOnce [SCHED_LAST + 1][2]sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetPriorityMax returns the maximum priority value that can be used with the
|
|
||||||
// scheduling algorithm identified by policy.
|
|
||||||
func (policy SchedPolicy) GetPriorityMax() (Int, error) {
|
|
||||||
schedPriorityOnce[policy][0].Do(func() {
|
|
||||||
priority, _, errno := syscall.Syscall(
|
|
||||||
syscall.SYS_SCHED_GET_PRIORITY_MAX,
|
|
||||||
uintptr(policy),
|
|
||||||
0, 0,
|
|
||||||
)
|
|
||||||
schedPriority[policy][0] = Int(priority)
|
|
||||||
if errno != 0 {
|
|
||||||
schedPriorityErr[policy][0] = errno
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return schedPriority[policy][0], schedPriorityErr[policy][0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPriorityMin returns the minimum priority value that can be used with the
|
|
||||||
// scheduling algorithm identified by policy.
|
|
||||||
func (policy SchedPolicy) GetPriorityMin() (Int, error) {
|
|
||||||
schedPriorityOnce[policy][1].Do(func() {
|
|
||||||
priority, _, errno := syscall.Syscall(
|
|
||||||
syscall.SYS_SCHED_GET_PRIORITY_MIN,
|
|
||||||
uintptr(policy),
|
|
||||||
0, 0,
|
|
||||||
)
|
|
||||||
schedPriority[policy][1] = Int(priority)
|
|
||||||
if errno != 0 {
|
|
||||||
schedPriorityErr[policy][1] = errno
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return schedPriority[policy][1], schedPriorityErr[policy][1]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
package std_test
|
package std_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"syscall"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container/std"
|
"hakurei.app/container/std"
|
||||||
@@ -24,90 +19,3 @@ func TestSyscallResolveName(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchedPolicyJSON(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
policy std.SchedPolicy
|
|
||||||
want string
|
|
||||||
encodeErr error
|
|
||||||
decodeErr error
|
|
||||||
}{
|
|
||||||
{std.SCHED_NORMAL, `""`, nil, nil},
|
|
||||||
{std.SCHED_FIFO, `"fifo"`, nil, nil},
|
|
||||||
{std.SCHED_RR, `"rr"`, nil, nil},
|
|
||||||
{std.SCHED_BATCH, `"batch"`, nil, nil},
|
|
||||||
{4, `"invalid policy 4"`, syscall.EINVAL, std.InvalidSchedPolicyError("invalid policy 4")},
|
|
||||||
{std.SCHED_IDLE, `"idle"`, nil, nil},
|
|
||||||
{std.SCHED_DEADLINE, `"deadline"`, nil, nil},
|
|
||||||
{std.SCHED_EXT, `"ext"`, nil, nil},
|
|
||||||
{math.MaxInt, `"iso"`, syscall.EINVAL, std.InvalidSchedPolicyError("iso")},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
name := tc.policy.String()
|
|
||||||
if tc.policy == std.SCHED_NORMAL {
|
|
||||||
name = "normal"
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
got, err := json.Marshal(tc.policy)
|
|
||||||
if !errors.Is(err, tc.encodeErr) {
|
|
||||||
t.Fatalf("Marshal: error = %v, want %v", err, tc.encodeErr)
|
|
||||||
}
|
|
||||||
if err == nil && string(got) != tc.want {
|
|
||||||
t.Fatalf("Marshal: %s, want %s", string(got), tc.want)
|
|
||||||
}
|
|
||||||
|
|
||||||
var v std.SchedPolicy
|
|
||||||
if err = json.Unmarshal([]byte(tc.want), &v); !reflect.DeepEqual(err, tc.decodeErr) {
|
|
||||||
t.Fatalf("Unmarshal: error = %v, want %v", err, tc.decodeErr)
|
|
||||||
}
|
|
||||||
if err == nil && v != tc.policy {
|
|
||||||
t.Fatalf("Unmarshal: %d, want %d", v, tc.policy)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSchedPolicyMinMax(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
policy std.SchedPolicy
|
|
||||||
min, max std.Int
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{std.SCHED_NORMAL, 0, 0, nil},
|
|
||||||
{std.SCHED_FIFO, 1, 99, nil},
|
|
||||||
{std.SCHED_RR, 1, 99, nil},
|
|
||||||
{std.SCHED_BATCH, 0, 0, nil},
|
|
||||||
{4, -1, -1, syscall.EINVAL},
|
|
||||||
{std.SCHED_IDLE, 0, 0, nil},
|
|
||||||
{std.SCHED_DEADLINE, 0, 0, nil},
|
|
||||||
{std.SCHED_EXT, 0, 0, nil},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
name := tc.policy.String()
|
|
||||||
if tc.policy == std.SCHED_NORMAL {
|
|
||||||
name = "normal"
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
if priority, err := tc.policy.GetPriorityMax(); !reflect.DeepEqual(err, tc.err) {
|
|
||||||
t.Fatalf("GetPriorityMax: error = %v, want %v", err, tc.err)
|
|
||||||
} else if priority != tc.max {
|
|
||||||
t.Fatalf("GetPriorityMax: %d, want %d", priority, tc.max)
|
|
||||||
}
|
|
||||||
if priority, err := tc.policy.GetPriorityMin(); !reflect.DeepEqual(err, tc.err) {
|
|
||||||
t.Fatalf("GetPriorityMin: error = %v, want %v", err, tc.err)
|
|
||||||
} else if priority != tc.min {
|
|
||||||
t.Fatalf("GetPriorityMin: %d, want %d", priority, tc.min)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -43,6 +43,18 @@ func Isatty(fd int) bool {
|
|||||||
return r == 0
|
return r == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// include/uapi/linux/sched.h
|
||||||
|
const (
|
||||||
|
SCHED_NORMAL = iota
|
||||||
|
SCHED_FIFO
|
||||||
|
SCHED_RR
|
||||||
|
SCHED_BATCH
|
||||||
|
_ // SCHED_ISO: reserved but not implemented yet
|
||||||
|
SCHED_IDLE
|
||||||
|
SCHED_DEADLINE
|
||||||
|
SCHED_EXT
|
||||||
|
)
|
||||||
|
|
||||||
// schedParam is equivalent to struct sched_param from include/linux/sched.h.
|
// schedParam is equivalent to struct sched_param from include/linux/sched.h.
|
||||||
type schedParam struct {
|
type schedParam struct {
|
||||||
// sched_priority
|
// sched_priority
|
||||||
@@ -62,13 +74,13 @@ type schedParam struct {
|
|||||||
// this if you do not have something similar in place!
|
// this if you do not have something similar in place!
|
||||||
//
|
//
|
||||||
// [very subtle to use correctly]: https://www.openwall.com/lists/musl/2016/03/01/4
|
// [very subtle to use correctly]: https://www.openwall.com/lists/musl/2016/03/01/4
|
||||||
func schedSetscheduler(tid int, policy std.SchedPolicy, param *schedParam) error {
|
func schedSetscheduler(tid, policy int, param *schedParam) error {
|
||||||
if _, _, errno := Syscall(
|
if r, _, errno := Syscall(
|
||||||
SYS_SCHED_SETSCHEDULER,
|
SYS_SCHED_SETSCHEDULER,
|
||||||
uintptr(tid),
|
uintptr(tid),
|
||||||
uintptr(policy),
|
uintptr(policy),
|
||||||
uintptr(unsafe.Pointer(param)),
|
uintptr(unsafe.Pointer(param)),
|
||||||
); errno != 0 {
|
); r < 0 {
|
||||||
return errno
|
return errno
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
12
flake.lock
generated
12
flake.lock
generated
@@ -7,11 +7,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1772985280,
|
"lastModified": 1765384171,
|
||||||
"narHash": "sha256-FdrNykOoY9VStevU4zjSUdvsL9SzJTcXt4omdEDZDLk=",
|
"narHash": "sha256-FuFtkJrW1Z7u+3lhzPRau69E0CNjADku1mLQQflUORo=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "8f736f007139d7f70752657dff6a401a585d6cbc",
|
"rev": "44777152652bc9eacf8876976fa72cc77ca8b9d8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1772822230,
|
"lastModified": 1765311797,
|
||||||
"narHash": "sha256-yf3iYLGbGVlIthlQIk5/4/EQDZNNEmuqKZkQssMljuw=",
|
"narHash": "sha256-mSD5Ob7a+T2RNjvPvOA1dkJHGVrNVl8ZOrAwBjKBDQo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "71caefce12ba78d84fe618cf61644dce01cf3a96",
|
"rev": "09eb77e94fa25202af8f3e81ddc7353d9970ac1b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
|
hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
|
||||||
inherit (pkgs)
|
inherit (pkgs)
|
||||||
# passthru.buildInputs
|
# passthru.buildInputs
|
||||||
go_1_26
|
go
|
||||||
clang
|
clang
|
||||||
|
|
||||||
# nativeBuildInputs
|
# nativeBuildInputs
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
let
|
let
|
||||||
# this is used for interactive vm testing during development, where tests might be broken
|
# this is used for interactive vm testing during development, where tests might be broken
|
||||||
package = self.packages.${pkgs.stdenv.hostPlatform.system}.hakurei.override {
|
package = self.packages.${pkgs.stdenv.hostPlatform.system}.hakurei.override {
|
||||||
buildGo126Module = previousArgs: pkgs.pkgsStatic.buildGo126Module (previousArgs // { doCheck = false; });
|
buildGoModule = previousArgs: pkgs.pkgsStatic.buildGoModule (previousArgs // { doCheck = false; });
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
142
hst/config.go
142
hst/config.go
@@ -6,137 +6,96 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/std"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config configures an application container.
|
// Config configures an application container, implemented in internal/app.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Reverse-DNS style configured arbitrary identifier string.
|
// Reverse-DNS style configured arbitrary identifier string.
|
||||||
//
|
// Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
|
||||||
// This value is passed as is to Wayland security-context-v1 and used as
|
|
||||||
// part of defaults in D-Bus session proxy. The zero value causes a default
|
|
||||||
// value to be derived from the container instance.
|
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
|
|
||||||
// System services to make available in the container.
|
// System services to make available in the container.
|
||||||
Enablements *Enablements `json:"enablements,omitempty"`
|
Enablements *Enablements `json:"enablements,omitempty"`
|
||||||
|
|
||||||
// Session D-Bus proxy configuration.
|
// Session D-Bus proxy configuration.
|
||||||
//
|
// If set to nil, session bus proxy assume built-in defaults.
|
||||||
// Has no effect if [EDBus] but is not set in Enablements. The zero value
|
|
||||||
// assumes built-in defaults derived from ID.
|
|
||||||
SessionBus *BusConfig `json:"session_bus,omitempty"`
|
SessionBus *BusConfig `json:"session_bus,omitempty"`
|
||||||
// System D-Bus proxy configuration.
|
// System D-Bus proxy configuration.
|
||||||
//
|
// If set to nil, system bus proxy is disabled.
|
||||||
// Has no effect if [EDBus] but is not set in Enablements. The zero value
|
|
||||||
// disables system bus proxy.
|
|
||||||
SystemBus *BusConfig `json:"system_bus,omitempty"`
|
SystemBus *BusConfig `json:"system_bus,omitempty"`
|
||||||
|
|
||||||
// Direct access to Wayland socket, no attempt is made to attach
|
// Direct access to wayland socket, no attempt is made to attach security-context-v1
|
||||||
// security-context-v1 and the bare socket is made available to the
|
// and the bare socket is made available to the container.
|
||||||
// container.
|
|
||||||
//
|
//
|
||||||
// This option is unsupported and will most likely enable full control over
|
// This option is unsupported and most likely enables full control over the Wayland
|
||||||
// the Wayland session from within the container. Do not set this to true
|
// session. Do not set this to true unless you are sure you know what you are doing.
|
||||||
// unless you are sure you know what you are doing.
|
|
||||||
DirectWayland bool `json:"direct_wayland,omitempty"`
|
DirectWayland bool `json:"direct_wayland,omitempty"`
|
||||||
|
// Direct access to the PipeWire socket established via SecurityContext::Create, no
|
||||||
// Direct access to the PipeWire socket established via SecurityContext::Create,
|
// attempt is made to start the pipewire-pulse server.
|
||||||
// no attempt is made to start the pipewire-pulse server.
|
|
||||||
//
|
//
|
||||||
// The SecurityContext machinery is fatally flawed, it unconditionally sets
|
// The SecurityContext machinery is fatally flawed, it blindly sets read and execute
|
||||||
// read and execute bits on all objects for clients with the lowest achievable
|
// bits on all objects for clients with the lowest achievable privilege level (by
|
||||||
// privilege level (by setting PW_KEY_ACCESS to "restricted" or by satisfying
|
// setting PW_KEY_ACCESS to "restricted"). This enables them to call any method
|
||||||
// all conditions of [the /.flatpak-info hack]). This enables them to call
|
// targeting any object, and since Registry::Destroy checks for the read and execute bit,
|
||||||
// any method targeting any object, and since Registry::Destroy checks for
|
// allows the destruction of any object other than PW_ID_CORE as well. This behaviour
|
||||||
// the read and execute bit, allows the destruction of any object other than
|
// is implemented separately in media-session and wireplumber, with the wireplumber
|
||||||
// PW_ID_CORE as well.
|
// implementation in Lua via an embedded Lua vm. In all known setups, wireplumber is
|
||||||
|
// in use, and there is no known way to change its behaviour and set permissions
|
||||||
|
// differently without replacing the Lua script. Also, since PipeWire relies on these
|
||||||
|
// permissions to work, reducing them is not possible.
|
||||||
//
|
//
|
||||||
// This behaviour is implemented separately in media-session and wireplumber,
|
// Currently, the only other sandboxed use case is flatpak, which is not aware of
|
||||||
// with the wireplumber implementation in Lua via an embedded Lua vm. In all
|
// PipeWire and blindly exposes the bare PulseAudio socket to the container (behaves
|
||||||
// known setups, wireplumber is in use, and in that case, no option for
|
// like DirectPulse). This socket is backed by the pipewire-pulse compatibility daemon,
|
||||||
// configuring this behaviour exists, without replacing the Lua script.
|
// which obtains client pid via the SO_PEERCRED option. The PipeWire daemon, pipewire-pulse
|
||||||
// Also, since PipeWire relies on these permissions to work, reducing them
|
// daemon and the session manager daemon then separately performs the /.flatpak-info hack
|
||||||
// was never possible in the first place.
|
// described in https://git.gensokyo.uk/security/hakurei/issues/21. Under such use case,
|
||||||
|
// since the client has no direct access to PipeWire, insecure parts of the protocol are
|
||||||
|
// obscured by pipewire-pulse simply not implementing them, and thus hiding the flaws
|
||||||
|
// described above.
|
||||||
//
|
//
|
||||||
// Currently, the only other sandboxed use case is flatpak, which is not
|
// Hakurei does not rely on the /.flatpak-info hack. Instead, a socket is sets up via
|
||||||
// aware of PipeWire and blindly exposes the bare PulseAudio socket to the
|
// SecurityContext. A pipewire-pulse server connected through it achieves the same
|
||||||
// container (behaves like DirectPulse). This socket is backed by the
|
// permissions as flatpak does via the /.flatpak-info hack and is maintained for the
|
||||||
// pipewire-pulse compatibility daemon, which obtains client pid via the
|
// life of the container.
|
||||||
// SO_PEERCRED option. The PipeWire daemon, pipewire-pulse daemon and the
|
|
||||||
// session manager daemon then separately performs [the /.flatpak-info hack].
|
|
||||||
// Under such use case, since the client has no direct access to PipeWire,
|
|
||||||
// insecure parts of the protocol are obscured by the absence of an
|
|
||||||
// equivalent API in PulseAudio, or pipewire-pulse simply not implementing
|
|
||||||
// them.
|
|
||||||
//
|
|
||||||
// Hakurei does not rely on [the /.flatpak-info hack]. Instead, a socket is
|
|
||||||
// sets up via SecurityContext. A pipewire-pulse server connected through it
|
|
||||||
// achieves the same permissions as flatpak does via [the /.flatpak-info hack]
|
|
||||||
// and is maintained for the life of the container.
|
|
||||||
//
|
|
||||||
// This option is unsupported and enables a denial-of-service attack as the
|
|
||||||
// sandboxed client is able to destroy any client object and thus
|
|
||||||
// disconnecting them from PipeWire, or destroy the SecurityContext object,
|
|
||||||
// preventing any further container creation.
|
|
||||||
//
|
//
|
||||||
|
// This option is unsupported and enables a denial-of-service attack as the sandboxed
|
||||||
|
// client is able to destroy any client object and thus disconnecting them from PipeWire,
|
||||||
|
// or destroy the SecurityContext object preventing any further container creation.
|
||||||
// Do not set this to true, it is insecure under any configuration.
|
// Do not set this to true, it is insecure under any configuration.
|
||||||
//
|
|
||||||
// [the /.flatpak-info hack]: https://git.gensokyo.uk/rosa/hakurei/issues/21
|
|
||||||
DirectPipeWire bool `json:"direct_pipewire,omitempty"`
|
DirectPipeWire bool `json:"direct_pipewire,omitempty"`
|
||||||
|
// Direct access to PulseAudio socket, no attempt is made to establish pipewire-pulse
|
||||||
// Direct access to PulseAudio socket, no attempt is made to establish
|
// server via a PipeWire socket with a SecurityContext attached and the bare socket
|
||||||
// pipewire-pulse server via a PipeWire socket with a SecurityContext
|
// is made available to the container.
|
||||||
// attached, and the bare socket is made available to the container.
|
|
||||||
//
|
//
|
||||||
// This option is unsupported and enables arbitrary code execution as the
|
// This option is unsupported and enables arbitrary code execution as the PulseAudio
|
||||||
// PulseAudio server.
|
// server. Do not set this to true, it is insecure under any configuration.
|
||||||
//
|
|
||||||
// Do not set this to true, it is insecure under any configuration.
|
|
||||||
DirectPulse bool `json:"direct_pulse,omitempty"`
|
DirectPulse bool `json:"direct_pulse,omitempty"`
|
||||||
|
|
||||||
// Extra acl updates to perform before setuid.
|
// Extra acl updates to perform before setuid.
|
||||||
ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"`
|
ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"`
|
||||||
|
|
||||||
// Numerical application id, passed to hsu, used to derive init user
|
// Numerical application id, passed to hsu, used to derive init user namespace credentials.
|
||||||
// namespace credentials.
|
|
||||||
Identity int `json:"identity"`
|
Identity int `json:"identity"`
|
||||||
// Init user namespace supplementary groups inherited by all container processes.
|
// Init user namespace supplementary groups inherited by all container processes.
|
||||||
Groups []string `json:"groups"`
|
Groups []string `json:"groups"`
|
||||||
|
|
||||||
// Scheduling policy to set for the container.
|
|
||||||
//
|
|
||||||
// The zero value retains the current scheduling policy.
|
|
||||||
SchedPolicy std.SchedPolicy `json:"sched_policy,omitempty"`
|
|
||||||
// Scheduling priority to set for the container.
|
|
||||||
//
|
|
||||||
// The zero value implies the minimum priority of the current SchedPolicy.
|
|
||||||
// Has no effect if SchedPolicy is zero.
|
|
||||||
SchedPriority std.Int `json:"sched_priority,omitempty"`
|
|
||||||
|
|
||||||
// High level configuration applied to the underlying [container].
|
// High level configuration applied to the underlying [container].
|
||||||
Container *ContainerConfig `json:"container"`
|
Container *ContainerConfig `json:"container"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrConfigNull is returned by [Config.Validate] for an invalid configuration
|
// ErrConfigNull is returned by [Config.Validate] for an invalid configuration that contains a null value for any
|
||||||
// that contains a null value for any field that must not be null.
|
// field that must not be null.
|
||||||
ErrConfigNull = errors.New("unexpected null in config")
|
ErrConfigNull = errors.New("unexpected null in config")
|
||||||
|
|
||||||
// ErrIdentityBounds is returned by [Config.Validate] for an out of bounds
|
// ErrIdentityBounds is returned by [Config.Validate] for an out of bounds [Config.Identity] value.
|
||||||
// [Config.Identity] value.
|
|
||||||
ErrIdentityBounds = errors.New("identity out of bounds")
|
ErrIdentityBounds = errors.New("identity out of bounds")
|
||||||
|
|
||||||
// ErrSchedPolicyBounds is returned by [Config.Validate] for an out of bounds
|
// ErrEnviron is returned by [Config.Validate] if an environment variable name contains '=' or NUL.
|
||||||
// [Config.SchedPolicy] value.
|
|
||||||
ErrSchedPolicyBounds = errors.New("scheduling policy out of bounds")
|
|
||||||
|
|
||||||
// ErrEnviron is returned by [Config.Validate] if an environment variable
|
|
||||||
// name contains '=' or NUL.
|
|
||||||
ErrEnviron = errors.New("invalid environment variable name")
|
ErrEnviron = errors.New("invalid environment variable name")
|
||||||
|
|
||||||
// ErrInsecure is returned by [Config.Validate] if the configuration is
|
// ErrInsecure is returned by [Config.Validate] if the configuration is considered insecure.
|
||||||
// considered insecure.
|
|
||||||
ErrInsecure = errors.New("configuration is insecure")
|
ErrInsecure = errors.New("configuration is insecure")
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -153,13 +112,6 @@ func (config *Config) Validate() error {
|
|||||||
Msg: "identity " + strconv.Itoa(config.Identity) + " out of range"}
|
Msg: "identity " + strconv.Itoa(config.Identity) + " out of range"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.SchedPolicy < 0 || config.SchedPolicy > std.SCHED_LAST {
|
|
||||||
return &AppError{Step: "validate configuration", Err: ErrSchedPolicyBounds,
|
|
||||||
Msg: "scheduling policy " +
|
|
||||||
strconv.Itoa(int(config.SchedPolicy)) +
|
|
||||||
" out of range"}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.SessionBus.CheckInterfaces("session"); err != nil {
|
if err := config.SessionBus.CheckInterfaces("session"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ func TestConfigValidate(t *testing.T) {
|
|||||||
Msg: "identity -1 out of range"}},
|
Msg: "identity -1 out of range"}},
|
||||||
{"identity upper", &hst.Config{Identity: 10000}, &hst.AppError{Step: "validate configuration", Err: hst.ErrIdentityBounds,
|
{"identity upper", &hst.Config{Identity: 10000}, &hst.AppError{Step: "validate configuration", Err: hst.ErrIdentityBounds,
|
||||||
Msg: "identity 10000 out of range"}},
|
Msg: "identity 10000 out of range"}},
|
||||||
{"sched lower", &hst.Config{SchedPolicy: -1}, &hst.AppError{Step: "validate configuration", Err: hst.ErrSchedPolicyBounds,
|
|
||||||
Msg: "scheduling policy -1 out of range"}},
|
|
||||||
{"sched upper", &hst.Config{SchedPolicy: 0xcafe}, &hst.AppError{Step: "validate configuration", Err: hst.ErrSchedPolicyBounds,
|
|
||||||
Msg: "scheduling policy 51966 out of range"}},
|
|
||||||
{"dbus session", &hst.Config{SessionBus: &hst.BusConfig{See: []string{""}}},
|
{"dbus session", &hst.Config{SessionBus: &hst.BusConfig{See: []string{""}}},
|
||||||
&hst.BadInterfaceError{Interface: "", Segment: "session"}},
|
&hst.BadInterfaceError{Interface: "", Segment: "session"}},
|
||||||
{"dbus system", &hst.Config{SystemBus: &hst.BusConfig{See: []string{""}}},
|
{"dbus system", &hst.Config{SystemBus: &hst.BusConfig{See: []string{""}}},
|
||||||
|
|||||||
@@ -16,20 +16,18 @@ const PrivateTmp = "/.hakurei"
|
|||||||
var AbsPrivateTmp = check.MustAbs(PrivateTmp)
|
var AbsPrivateTmp = check.MustAbs(PrivateTmp)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// WaitDelayDefault is used when WaitDelay has the zero value.
|
// WaitDelayDefault is used when WaitDelay has its zero value.
|
||||||
WaitDelayDefault = 5 * time.Second
|
WaitDelayDefault = 5 * time.Second
|
||||||
// WaitDelayMax is used when WaitDelay exceeds its value.
|
// WaitDelayMax is used if WaitDelay exceeds its value.
|
||||||
WaitDelayMax = 30 * time.Second
|
WaitDelayMax = 30 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ExitFailure is returned if the container fails to start.
|
// ExitFailure is returned if the container fails to start.
|
||||||
ExitFailure = iota + 1
|
ExitFailure = iota + 1
|
||||||
// ExitCancel is returned if the container is terminated by a shim-directed
|
// ExitCancel is returned if the container is terminated by a shim-directed signal which cancels its context.
|
||||||
// signal which cancels its context.
|
|
||||||
ExitCancel
|
ExitCancel
|
||||||
// ExitOrphan is returned when the shim is orphaned before priv side process
|
// ExitOrphan is returned when the shim is orphaned before priv side delivers a signal.
|
||||||
// delivers a signal.
|
|
||||||
ExitOrphan
|
ExitOrphan
|
||||||
|
|
||||||
// ExitRequest is returned when the priv side process requests shim exit.
|
// ExitRequest is returned when the priv side process requests shim exit.
|
||||||
@@ -40,12 +38,10 @@ const (
|
|||||||
type Flags uintptr
|
type Flags uintptr
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// FMultiarch unblocks system calls required for multiarch to work on
|
// FMultiarch unblocks syscalls required for multiarch to work on applicable targets.
|
||||||
// multiarch-enabled targets (amd64, arm64).
|
|
||||||
FMultiarch Flags = 1 << iota
|
FMultiarch Flags = 1 << iota
|
||||||
|
|
||||||
// FSeccompCompat changes emitted seccomp filter programs to be identical to
|
// FSeccompCompat changes emitted seccomp filter programs to be identical to that of Flatpak.
|
||||||
// that of Flatpak in enabled rulesets.
|
|
||||||
FSeccompCompat
|
FSeccompCompat
|
||||||
// FDevel unblocks ptrace and friends.
|
// FDevel unblocks ptrace and friends.
|
||||||
FDevel
|
FDevel
|
||||||
@@ -58,15 +54,12 @@ const (
|
|||||||
// FTty unblocks dangerous terminal I/O (faking input).
|
// FTty unblocks dangerous terminal I/O (faking input).
|
||||||
FTty
|
FTty
|
||||||
|
|
||||||
// FMapRealUID maps the target user uid to the privileged user uid in the
|
// FMapRealUID maps the target user uid to the privileged user uid in the container user namespace.
|
||||||
// container user namespace.
|
// Some programs fail to connect to dbus session running as a different uid,
|
||||||
//
|
// this option works around it by mapping priv-side caller uid in container.
|
||||||
// Some programs fail to connect to dbus session running as a different uid,
|
|
||||||
// this option works around it by mapping priv-side caller uid in container.
|
|
||||||
FMapRealUID
|
FMapRealUID
|
||||||
|
|
||||||
// FDevice mount /dev/ from the init mount namespace as is in the container
|
// FDevice mount /dev/ from the init mount namespace as-is in the container mount namespace.
|
||||||
// mount namespace.
|
|
||||||
FDevice
|
FDevice
|
||||||
|
|
||||||
// FShareRuntime shares XDG_RUNTIME_DIR between containers under the same identity.
|
// FShareRuntime shares XDG_RUNTIME_DIR between containers under the same identity.
|
||||||
@@ -119,37 +112,30 @@ func (flags Flags) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerConfig describes the container configuration to be applied to an
|
// ContainerConfig describes the container configuration to be applied to an underlying [container].
|
||||||
// underlying [container]. It is validated by [Config.Validate].
|
|
||||||
type ContainerConfig struct {
|
type ContainerConfig struct {
|
||||||
// Container UTS namespace hostname.
|
// Container UTS namespace hostname.
|
||||||
Hostname string `json:"hostname,omitempty"`
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
|
||||||
// Duration in nanoseconds to wait for after interrupting the initial process.
|
// Duration in nanoseconds to wait for after interrupting the initial process.
|
||||||
//
|
// Defaults to [WaitDelayDefault] if zero, or [WaitDelayMax] if greater than [WaitDelayMax].
|
||||||
// Defaults to [WaitDelayDefault] if zero, or [WaitDelayMax] if greater than
|
// Values lesser than zero is equivalent to zero, bypassing [WaitDelayDefault].
|
||||||
// [WaitDelayMax]. Values lesser than zero is equivalent to zero, bypassing
|
|
||||||
// [WaitDelayDefault].
|
|
||||||
WaitDelay time.Duration `json:"wait_delay,omitempty"`
|
WaitDelay time.Duration `json:"wait_delay,omitempty"`
|
||||||
|
|
||||||
// Initial process environment variables.
|
// Initial process environment variables.
|
||||||
Env map[string]string `json:"env"`
|
Env map[string]string `json:"env"`
|
||||||
|
|
||||||
// Container mount points.
|
/* Container mount points.
|
||||||
//
|
|
||||||
// If the first element targets /, it is inserted early and excluded from
|
If the first element targets /, it is inserted early and excluded from path hiding. */
|
||||||
// path hiding. Otherwise, an anonymous instance of tmpfs is set up on /.
|
|
||||||
Filesystem []FilesystemConfigJSON `json:"filesystem"`
|
Filesystem []FilesystemConfigJSON `json:"filesystem"`
|
||||||
|
|
||||||
// String used as the username of the emulated user, validated against the
|
// String used as the username of the emulated user, validated against the default NAME_REGEX from adduser.
|
||||||
// default NAME_REGEX from adduser.
|
|
||||||
//
|
|
||||||
// Defaults to passwd name of target uid or chronos.
|
// Defaults to passwd name of target uid or chronos.
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
// Pathname of shell in the container filesystem to use for the emulated user.
|
// Pathname of shell in the container filesystem to use for the emulated user.
|
||||||
Shell *check.Absolute `json:"shell"`
|
Shell *check.Absolute `json:"shell"`
|
||||||
// Directory in the container filesystem to enter and use as the home
|
// Directory in the container filesystem to enter and use as the home directory of the emulated user.
|
||||||
// directory of the emulated user.
|
|
||||||
Home *check.Absolute `json:"home"`
|
Home *check.Absolute `json:"home"`
|
||||||
|
|
||||||
// Pathname to executable file in the container filesystem.
|
// Pathname to executable file in the container filesystem.
|
||||||
@@ -162,7 +148,6 @@ type ContainerConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ContainerConfigF is [ContainerConfig] stripped of its methods.
|
// ContainerConfigF is [ContainerConfig] stripped of its methods.
|
||||||
//
|
|
||||||
// The [ContainerConfig.Flags] field does not survive a [json] round trip.
|
// The [ContainerConfig.Flags] field does not survive a [json] round trip.
|
||||||
type ContainerConfigF ContainerConfig
|
type ContainerConfigF ContainerConfig
|
||||||
|
|
||||||
|
|||||||
46
hst/dbus.go
46
hst/dbus.go
@@ -5,26 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BadInterfaceError is returned when Interface fails an undocumented check in
|
// BadInterfaceError is returned when Interface fails an undocumented check in xdg-dbus-proxy,
|
||||||
// xdg-dbus-proxy, which would have cause a silent failure.
|
// which would have cause a silent failure.
|
||||||
//
|
|
||||||
// xdg-dbus-proxy fails without output when this condition is not met:
|
|
||||||
//
|
|
||||||
// char *dot = strrchr (filter->interface, '.');
|
|
||||||
// if (dot != NULL)
|
|
||||||
// {
|
|
||||||
// *dot = 0;
|
|
||||||
// if (strcmp (dot + 1, "*") != 0)
|
|
||||||
// filter->member = g_strdup (dot + 1);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// trim ".*" since they are removed before searching for '.':
|
|
||||||
//
|
|
||||||
// if (g_str_has_suffix (name, ".*"))
|
|
||||||
// {
|
|
||||||
// name[strlen (name) - 2] = 0;
|
|
||||||
// wildcard = TRUE;
|
|
||||||
// }
|
|
||||||
type BadInterfaceError struct {
|
type BadInterfaceError struct {
|
||||||
// Interface is the offending interface string.
|
// Interface is the offending interface string.
|
||||||
Interface string
|
Interface string
|
||||||
@@ -37,8 +19,7 @@ func (e *BadInterfaceError) Error() string {
|
|||||||
if e == nil {
|
if e == nil {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
}
|
}
|
||||||
return "bad interface string " + strconv.Quote(e.Interface) +
|
return "bad interface string " + strconv.Quote(e.Interface) + " in " + e.Segment + " bus configuration"
|
||||||
" in " + e.Segment + " bus configuration"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BusConfig configures the xdg-dbus-proxy process.
|
// BusConfig configures the xdg-dbus-proxy process.
|
||||||
@@ -95,14 +76,31 @@ func (c *BusConfig) Interfaces(yield func(string) bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckInterfaces checks for invalid interface strings based on an undocumented
|
// CheckInterfaces checks for invalid interface strings based on an undocumented check in xdg-dbus-error,
|
||||||
// check in xdg-dbus-error, returning [BadInterfaceError] if one is encountered.
|
// returning [BadInterfaceError] if one is encountered.
|
||||||
func (c *BusConfig) CheckInterfaces(segment string) error {
|
func (c *BusConfig) CheckInterfaces(segment string) error {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for iface := range c.Interfaces {
|
for iface := range c.Interfaces {
|
||||||
|
/*
|
||||||
|
xdg-dbus-proxy fails without output when this condition is not met:
|
||||||
|
char *dot = strrchr (filter->interface, '.');
|
||||||
|
if (dot != NULL)
|
||||||
|
{
|
||||||
|
*dot = 0;
|
||||||
|
if (strcmp (dot + 1, "*") != 0)
|
||||||
|
filter->member = g_strdup (dot + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
trim ".*" since they are removed before searching for '.':
|
||||||
|
if (g_str_has_suffix (name, ".*"))
|
||||||
|
{
|
||||||
|
name[strlen (name) - 2] = 0;
|
||||||
|
wildcard = TRUE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
if strings.IndexByte(strings.TrimSuffix(iface, ".*"), '.') == -1 {
|
if strings.IndexByte(strings.TrimSuffix(iface, ".*"), '.') == -1 {
|
||||||
return &BadInterfaceError{iface, segment}
|
return &BadInterfaceError{iface, segment}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,17 +11,15 @@ import (
|
|||||||
type Enablement byte
|
type Enablement byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// EWayland exposes a Wayland pathname socket via security-context-v1.
|
// EWayland exposes a wayland pathname socket via security-context-v1.
|
||||||
EWayland Enablement = 1 << iota
|
EWayland Enablement = 1 << iota
|
||||||
// EX11 adds the target user via X11 ChangeHosts and exposes the X11
|
// EX11 adds the target user via X11 ChangeHosts and exposes the X11 pathname socket.
|
||||||
// pathname socket.
|
|
||||||
EX11
|
EX11
|
||||||
// EDBus enables the per-container xdg-dbus-proxy daemon.
|
// EDBus enables the per-container xdg-dbus-proxy daemon.
|
||||||
EDBus
|
EDBus
|
||||||
// EPipeWire exposes a pipewire pathname socket via SecurityContext.
|
// EPipeWire exposes a pipewire pathname socket via SecurityContext.
|
||||||
EPipeWire
|
EPipeWire
|
||||||
// EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the
|
// EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the PulseAudio socket.
|
||||||
// PulseAudio socket.
|
|
||||||
EPulse
|
EPulse
|
||||||
|
|
||||||
// EM is a noop.
|
// EM is a noop.
|
||||||
|
|||||||
15
hst/fs.go
15
hst/fs.go
@@ -24,8 +24,7 @@ type FilesystemConfig interface {
|
|||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Ops interface enables [FilesystemConfig] to queue container ops without
|
// The Ops interface enables [FilesystemConfig] to queue container ops without depending on the container package.
|
||||||
// depending on the container package.
|
|
||||||
type Ops interface {
|
type Ops interface {
|
||||||
// Tmpfs appends an op that mounts tmpfs on a container path.
|
// Tmpfs appends an op that mounts tmpfs on a container path.
|
||||||
Tmpfs(target *check.Absolute, size int, perm os.FileMode) Ops
|
Tmpfs(target *check.Absolute, size int, perm os.FileMode) Ops
|
||||||
@@ -42,15 +41,12 @@ type Ops interface {
|
|||||||
// Link appends an op that creates a symlink in the container filesystem.
|
// Link appends an op that creates a symlink in the container filesystem.
|
||||||
Link(target *check.Absolute, linkName string, dereference bool) Ops
|
Link(target *check.Absolute, linkName string, dereference bool) Ops
|
||||||
|
|
||||||
// Root appends an op that expands a directory into a toplevel bind mount
|
// Root appends an op that expands a directory into a toplevel bind mount mirror on container root.
|
||||||
// mirror on container root.
|
|
||||||
Root(host *check.Absolute, flags int) Ops
|
Root(host *check.Absolute, flags int) Ops
|
||||||
// Etc appends an op that expands host /etc into a toplevel symlink mirror
|
// Etc appends an op that expands host /etc into a toplevel symlink mirror with /etc semantics.
|
||||||
// with /etc semantics.
|
|
||||||
Etc(host *check.Absolute, prefix string) Ops
|
Etc(host *check.Absolute, prefix string) Ops
|
||||||
|
|
||||||
// Daemon appends an op that starts a daemon in the container and blocks
|
// Daemon appends an op that starts a daemon in the container and blocks until target appears.
|
||||||
// until target appears.
|
|
||||||
Daemon(target, path *check.Absolute, args ...string) Ops
|
Daemon(target, path *check.Absolute, args ...string) Ops
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,8 +61,7 @@ type ApplyState struct {
|
|||||||
// ErrFSNull is returned by [json] on encountering a null [FilesystemConfig] value.
|
// ErrFSNull is returned by [json] on encountering a null [FilesystemConfig] value.
|
||||||
var ErrFSNull = errors.New("unexpected null in mount point")
|
var ErrFSNull = errors.New("unexpected null in mount point")
|
||||||
|
|
||||||
// FSTypeError is returned when [ContainerConfig.Filesystem] contains an entry
|
// FSTypeError is returned when [ContainerConfig.Filesystem] contains an entry with invalid type.
|
||||||
// with invalid type.
|
|
||||||
type FSTypeError string
|
type FSTypeError string
|
||||||
|
|
||||||
func (f FSTypeError) Error() string { return fmt.Sprintf("invalid filesystem type %q", string(f)) }
|
func (f FSTypeError) Error() string { return fmt.Sprintf("invalid filesystem type %q", string(f)) }
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ type FSLink struct {
|
|||||||
Target *check.Absolute `json:"dst"`
|
Target *check.Absolute `json:"dst"`
|
||||||
// Arbitrary linkname value store in the symlink.
|
// Arbitrary linkname value store in the symlink.
|
||||||
Linkname string `json:"linkname"`
|
Linkname string `json:"linkname"`
|
||||||
|
// Whether to treat Linkname as an absolute pathname and dereference before creating the link.
|
||||||
// Whether to treat Linkname as an absolute pathname and dereference before
|
|
||||||
// creating the link.
|
|
||||||
Dereference bool `json:"dereference,omitempty"`
|
Dereference bool `json:"dereference,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ type FSOverlay struct {
|
|||||||
|
|
||||||
// Any filesystem, does not need to be on a writable filesystem, must not be nil.
|
// Any filesystem, does not need to be on a writable filesystem, must not be nil.
|
||||||
Lower []*check.Absolute `json:"lower"`
|
Lower []*check.Absolute `json:"lower"`
|
||||||
// The upperdir is normally on a writable filesystem, leave as nil to mount
|
// The upperdir is normally on a writable filesystem, leave as nil to mount Lower readonly.
|
||||||
// Lower readonly.
|
|
||||||
Upper *check.Absolute `json:"upper,omitempty"`
|
Upper *check.Absolute `json:"upper,omitempty"`
|
||||||
// The workdir needs to be an empty directory on the same filesystem as
|
// The workdir needs to be an empty directory on the same filesystem as Upper, must not be nil if Upper is populated.
|
||||||
// Upper, must not be nil if Upper is populated.
|
|
||||||
Work *check.Absolute `json:"work,omitempty"`
|
Work *check.Absolute `json:"work,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
hst/hst.go
60
hst/hst.go
@@ -44,13 +44,11 @@ func (e *AppError) Message() string {
|
|||||||
type Paths struct {
|
type Paths struct {
|
||||||
// Temporary directory returned by [os.TempDir], usually equivalent to [fhs.AbsTmp].
|
// Temporary directory returned by [os.TempDir], usually equivalent to [fhs.AbsTmp].
|
||||||
TempDir *check.Absolute `json:"temp_dir"`
|
TempDir *check.Absolute `json:"temp_dir"`
|
||||||
// Shared directory specific to the hsu userid, usually
|
// Shared directory specific to the hsu userid, usually (`/tmp/hakurei.%d`, [Info.User]).
|
||||||
// (`/tmp/hakurei.%d`, [Info.User]).
|
|
||||||
SharePath *check.Absolute `json:"share_path"`
|
SharePath *check.Absolute `json:"share_path"`
|
||||||
// Checked XDG_RUNTIME_DIR value, usually (`/run/user/%d`, uid).
|
// Checked XDG_RUNTIME_DIR value, usually (`/run/user/%d`, uid).
|
||||||
RuntimePath *check.Absolute `json:"runtime_path"`
|
RuntimePath *check.Absolute `json:"runtime_path"`
|
||||||
// Shared directory specific to the hsu userid located in RuntimePath,
|
// Shared directory specific to the hsu userid located in RuntimePath, usually (`/run/user/%d/hakurei`, uid).
|
||||||
// usually (`/run/user/%d/hakurei`, uid).
|
|
||||||
RunDirPath *check.Absolute `json:"run_dir_path"`
|
RunDirPath *check.Absolute `json:"run_dir_path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,23 +74,10 @@ func Template() *Config {
|
|||||||
|
|
||||||
SessionBus: &BusConfig{
|
SessionBus: &BusConfig{
|
||||||
See: nil,
|
See: nil,
|
||||||
Talk: []string{
|
Talk: []string{"org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
|
||||||
"org.freedesktop.Notifications",
|
"org.freedesktop.secrets", "org.kde.kwalletd5", "org.kde.kwalletd6", "org.gnome.SessionManager"},
|
||||||
"org.freedesktop.FileManager1",
|
Own: []string{"org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||||
"org.freedesktop.ScreenSaver",
|
"org.mpris.MediaPlayer2.chromium.*"},
|
||||||
"org.freedesktop.secrets",
|
|
||||||
|
|
||||||
"org.kde.kwalletd5",
|
|
||||||
"org.kde.kwalletd6",
|
|
||||||
|
|
||||||
"org.gnome.SessionManager",
|
|
||||||
},
|
|
||||||
Own: []string{
|
|
||||||
"org.chromium.Chromium.*",
|
|
||||||
|
|
||||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.chromium.*",
|
|
||||||
},
|
|
||||||
Call: map[string]string{"org.freedesktop.portal.*": "*"},
|
Call: map[string]string{"org.freedesktop.portal.*": "*"},
|
||||||
Broadcast: map[string]string{"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"},
|
Broadcast: map[string]string{"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"},
|
||||||
Log: false,
|
Log: false,
|
||||||
@@ -127,12 +112,7 @@ func Template() *Config {
|
|||||||
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT",
|
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT",
|
||||||
},
|
},
|
||||||
Filesystem: []FilesystemConfigJSON{
|
Filesystem: []FilesystemConfigJSON{
|
||||||
{&FSBind{
|
{&FSBind{Target: fhs.AbsRoot, Source: fhs.AbsVarLib.Append("hakurei/base/org.debian"), Write: true, Special: true}},
|
||||||
Target: fhs.AbsRoot,
|
|
||||||
Source: fhs.AbsVarLib.Append("hakurei/base/org.debian"),
|
|
||||||
Write: true,
|
|
||||||
Special: true,
|
|
||||||
}},
|
|
||||||
{&FSBind{Target: fhs.AbsEtc, Source: fhs.AbsEtc, Special: true}},
|
{&FSBind{Target: fhs.AbsEtc, Source: fhs.AbsEtc, Special: true}},
|
||||||
{&FSEphemeral{Target: fhs.AbsTmp, Write: true, Perm: 0755}},
|
{&FSEphemeral{Target: fhs.AbsTmp, Write: true, Perm: 0755}},
|
||||||
{&FSOverlay{
|
{&FSOverlay{
|
||||||
@@ -141,27 +121,11 @@ func Template() *Config {
|
|||||||
Upper: fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
Upper: fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
||||||
Work: fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/work"),
|
Work: fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/work"),
|
||||||
}},
|
}},
|
||||||
{&FSLink{
|
{&FSLink{Target: fhs.AbsRun.Append("current-system"), Linkname: "/run/current-system", Dereference: true}},
|
||||||
Target: fhs.AbsRun.Append("current-system"),
|
{&FSLink{Target: fhs.AbsRun.Append("opengl-driver"), Linkname: "/run/opengl-driver", Dereference: true}},
|
||||||
Linkname: "/run/current-system",
|
{&FSBind{Source: fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
|
||||||
Dereference: true,
|
Target: check.MustAbs("/data/data/org.chromium.Chromium"), Write: true, Ensure: true}},
|
||||||
}},
|
{&FSBind{Source: fhs.AbsDev.Append("dri"), Device: true, Optional: true}},
|
||||||
{&FSLink{
|
|
||||||
Target: fhs.AbsRun.Append("opengl-driver"),
|
|
||||||
Linkname: "/run/opengl-driver",
|
|
||||||
Dereference: true,
|
|
||||||
}},
|
|
||||||
{&FSBind{
|
|
||||||
Source: fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
|
|
||||||
Target: check.MustAbs("/data/data/org.chromium.Chromium"),
|
|
||||||
Write: true,
|
|
||||||
Ensure: true,
|
|
||||||
}},
|
|
||||||
{&FSBind{
|
|
||||||
Source: fhs.AbsDev.Append("dri"),
|
|
||||||
Device: true,
|
|
||||||
Optional: true,
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Username: "chronos",
|
Username: "chronos",
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ import (
|
|||||||
// An ID is a unique identifier held by a running hakurei container.
|
// An ID is a unique identifier held by a running hakurei container.
|
||||||
type ID [16]byte
|
type ID [16]byte
|
||||||
|
|
||||||
// ErrIdentifierLength is returned when encountering a [hex] representation of
|
// ErrIdentifierLength is returned when encountering a [hex] representation of [ID] with unexpected length.
|
||||||
// [ID] with unexpected length.
|
|
||||||
var ErrIdentifierLength = errors.New("identifier string has unexpected length")
|
var ErrIdentifierLength = errors.New("identifier string has unexpected length")
|
||||||
|
|
||||||
// IdentifierDecodeError is returned by [ID.UnmarshalText] to provide relevant
|
// IdentifierDecodeError is returned by [ID.UnmarshalText] to provide relevant error descriptions.
|
||||||
// error descriptions.
|
|
||||||
type IdentifierDecodeError struct{ Err error }
|
type IdentifierDecodeError struct{ Err error }
|
||||||
|
|
||||||
func (e IdentifierDecodeError) Unwrap() error { return e.Err }
|
func (e IdentifierDecodeError) Unwrap() error { return e.Err }
|
||||||
@@ -25,10 +23,7 @@ func (e IdentifierDecodeError) Error() string {
|
|||||||
var invalidByteError hex.InvalidByteError
|
var invalidByteError hex.InvalidByteError
|
||||||
switch {
|
switch {
|
||||||
case errors.As(e.Err, &invalidByteError):
|
case errors.As(e.Err, &invalidByteError):
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf("got invalid byte %#U in identifier", rune(invalidByteError))
|
||||||
"got invalid byte %#U in identifier",
|
|
||||||
rune(invalidByteError),
|
|
||||||
)
|
|
||||||
case errors.Is(e.Err, hex.ErrLength):
|
case errors.Is(e.Err, hex.ErrLength):
|
||||||
return "odd length identifier hex string"
|
return "odd length identifier hex string"
|
||||||
|
|
||||||
@@ -46,9 +41,7 @@ func (a *ID) CreationTime() time.Time {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewInstanceID creates a new unique [ID].
|
// NewInstanceID creates a new unique [ID].
|
||||||
func NewInstanceID(id *ID) error {
|
func NewInstanceID(id *ID) error { return newInstanceID(id, uint64(time.Now().UnixNano())) }
|
||||||
return newInstanceID(id, uint64(time.Now().UnixNano()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// newInstanceID creates a new unique [ID] with the specified timestamp.
|
// newInstanceID creates a new unique [ID] with the specified timestamp.
|
||||||
func newInstanceID(id *ID, p uint64) error {
|
func newInstanceID(id *ID, p uint64) error {
|
||||||
|
|||||||
0
internal/azalea/azalea.bnf
Normal file
0
internal/azalea/azalea.bnf
Normal file
69
internal/azalea/azalea.go
Normal file
69
internal/azalea/azalea.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
//go:generate gocc -a azalea.bnf
|
||||||
|
package azalea
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"hakurei.app/container/check"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
Generator
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParser(gen Generator) *Parser {
|
||||||
|
return &Parser{
|
||||||
|
Generator: gen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (p Parser) Initialise() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Parser) Consume(ns string, file io.Reader) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeDir walks a directory and consumes all Azalea source files within it and all its subdirectories, as long as they end with the .az extension.
|
||||||
|
func (p Parser) ConsumeDir(dir *check.Absolute) error {
|
||||||
|
ds := dir.String()
|
||||||
|
return filepath.WalkDir(ds, func(path string, d fs.DirEntry, err error) (e error) {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.IsDir() || !strings.HasSuffix(d.Name(), ".az") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rel, e := filepath.Rel(ds, path)
|
||||||
|
ns := strings.TrimSuffix(rel, ".az")
|
||||||
|
f, e := os.Open(path)
|
||||||
|
return p.Consume(ns, f)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeAll consumes all provided readers as Azalea source code, each given the namespace `r%d` where `%d` is the index of the reader in the provided arguments.
|
||||||
|
func (p Parser) ConsumeAll(in ...io.Reader) error {
|
||||||
|
for i, r := range in {
|
||||||
|
err := p.Consume("r"+strconv.FormatInt(int64(i), 10), r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeStrings consumes all provided strings as Azalea source code, each given the namespace `s%d` where `%d` is the index of the string in the provided arugments.
|
||||||
|
func (p Parser) ConsumeStrings(in ...string) error {
|
||||||
|
for i, s := range in {
|
||||||
|
err := p.Consume("s"+strconv.FormatInt(int64(i), 10), strings.NewReader(s))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
36
internal/azalea/generator.go
Normal file
36
internal/azalea/generator.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package azalea
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Generator interface {
|
||||||
|
Finalise() (error, io.Writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JsonGenerator struct {
|
||||||
|
t any
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJsonGenerator[T any]() JsonGenerator {
|
||||||
|
t := new(T)
|
||||||
|
|
||||||
|
return JsonGenerator{
|
||||||
|
t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JsonGenerator) Finalise() (error, io.Writer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type PkgIRGenerator struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPkgIRGenerator() PkgIRGenerator {
|
||||||
|
return PkgIRGenerator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PkgIRGenerator) Finalise() (error, io.Writer) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -38,7 +38,6 @@ func (h *Hsu) ensureDispatcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the current user hsurc identifier.
|
// ID returns the current user hsurc identifier.
|
||||||
//
|
|
||||||
// [ErrHsuAccess] is returned if the current user is not in hsurc.
|
// [ErrHsuAccess] is returned if the current user is not in hsurc.
|
||||||
func (h *Hsu) ID() (int, error) {
|
func (h *Hsu) ID() (int, error) {
|
||||||
h.ensureDispatcher()
|
h.ensureDispatcher()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Package outcome implements the outcome of the privileged and container sides
|
// Package outcome implements the outcome of the privileged and container sides of a hakurei container.
|
||||||
// of a hakurei container.
|
|
||||||
package outcome
|
package outcome
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -28,9 +27,8 @@ func Info() *hst.Info {
|
|||||||
return &hi
|
return &hi
|
||||||
}
|
}
|
||||||
|
|
||||||
// envAllocSize is the initial size of the env map pre-allocated when the
|
// envAllocSize is the initial size of the env map pre-allocated when the configured env map is nil.
|
||||||
// configured env map is nil. It should be large enough to fit all insertions by
|
// It should be large enough to fit all insertions by outcomeOp.toContainer.
|
||||||
// outcomeOp.toContainer.
|
|
||||||
const envAllocSize = 1 << 6
|
const envAllocSize = 1 << 6
|
||||||
|
|
||||||
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
||||||
@@ -45,8 +43,7 @@ func (s *stringPair[T]) unwrap() T { return s.v }
|
|||||||
func (s *stringPair[T]) String() string { return s.s }
|
func (s *stringPair[T]) String() string { return s.s }
|
||||||
|
|
||||||
// outcomeState is copied to the shim process and available while applying outcomeOp.
|
// outcomeState is copied to the shim process and available while applying outcomeOp.
|
||||||
// This is transmitted from the priv side to the shim, so exported fields should
|
// This is transmitted from the priv side to the shim, so exported fields should be kept to a minimum.
|
||||||
// be kept to a minimum.
|
|
||||||
type outcomeState struct {
|
type outcomeState struct {
|
||||||
// Params only used by the shim process. Populated by populateEarly.
|
// Params only used by the shim process. Populated by populateEarly.
|
||||||
Shim *shimParams
|
Shim *shimParams
|
||||||
@@ -92,25 +89,14 @@ func (s *outcomeState) valid() bool {
|
|||||||
s.Paths != nil
|
s.Paths != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newOutcomeState returns the address of a new outcomeState with its exported
|
// newOutcomeState returns the address of a new outcomeState with its exported fields populated via syscallDispatcher.
|
||||||
// fields populated via syscallDispatcher.
|
|
||||||
func newOutcomeState(k syscallDispatcher, msg message.Msg, id *hst.ID, config *hst.Config, hsu *Hsu) *outcomeState {
|
func newOutcomeState(k syscallDispatcher, msg message.Msg, id *hst.ID, config *hst.Config, hsu *Hsu) *outcomeState {
|
||||||
s := outcomeState{
|
s := outcomeState{
|
||||||
Shim: &shimParams{
|
Shim: &shimParams{PrivPID: k.getpid(), Verbose: msg.IsVerbose()},
|
||||||
PrivPID: k.getpid(),
|
ID: id,
|
||||||
Verbose: msg.IsVerbose(),
|
Identity: config.Identity,
|
||||||
|
UserID: hsu.MustID(msg),
|
||||||
SchedPolicy: config.SchedPolicy,
|
Paths: env.CopyPathsFunc(k.fatalf, k.tempdir, func(key string) string { v, _ := k.lookupEnv(key); return v }),
|
||||||
SchedPriority: config.SchedPriority,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: id,
|
|
||||||
Identity: config.Identity,
|
|
||||||
UserID: hsu.MustID(msg),
|
|
||||||
Paths: env.CopyPathsFunc(k.fatalf, k.tempdir, func(key string) string {
|
|
||||||
v, _ := k.lookupEnv(key)
|
|
||||||
return v
|
|
||||||
}),
|
|
||||||
Container: config.Container,
|
Container: config.Container,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +121,6 @@ func newOutcomeState(k syscallDispatcher, msg message.Msg, id *hst.ID, config *h
|
|||||||
}
|
}
|
||||||
|
|
||||||
// populateLocal populates unexported fields from transmitted exported fields.
|
// populateLocal populates unexported fields from transmitted exported fields.
|
||||||
//
|
|
||||||
// These fields are cheaper to recompute per-process.
|
// These fields are cheaper to recompute per-process.
|
||||||
func (s *outcomeState) populateLocal(k syscallDispatcher, msg message.Msg) error {
|
func (s *outcomeState) populateLocal(k syscallDispatcher, msg message.Msg) error {
|
||||||
if !s.valid() || k == nil || msg == nil {
|
if !s.valid() || k == nil || msg == nil {
|
||||||
@@ -151,10 +136,7 @@ func (s *outcomeState) populateLocal(k syscallDispatcher, msg message.Msg) error
|
|||||||
s.id = &stringPair[hst.ID]{*s.ID, s.ID.String()}
|
s.id = &stringPair[hst.ID]{*s.ID, s.ID.String()}
|
||||||
|
|
||||||
s.Copy(&s.sc, s.UserID)
|
s.Copy(&s.sc, s.UserID)
|
||||||
msg.Verbosef(
|
msg.Verbosef("process share directory at %q, runtime directory at %q", s.sc.SharePath, s.sc.RunDirPath)
|
||||||
"process share directory at %q, runtime directory at %q",
|
|
||||||
s.sc.SharePath, s.sc.RunDirPath,
|
|
||||||
)
|
|
||||||
|
|
||||||
s.identity = newInt(s.Identity)
|
s.identity = newInt(s.Identity)
|
||||||
s.mapuid, s.mapgid = newInt(s.Mapuid), newInt(s.Mapgid)
|
s.mapuid, s.mapgid = newInt(s.Mapuid), newInt(s.Mapgid)
|
||||||
@@ -164,25 +146,17 @@ func (s *outcomeState) populateLocal(k syscallDispatcher, msg message.Msg) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// instancePath returns a path formatted for outcomeStateSys.instance.
|
// instancePath returns a path formatted for outcomeStateSys.instance.
|
||||||
//
|
|
||||||
// This method must only be called from outcomeOp.toContainer if
|
// This method must only be called from outcomeOp.toContainer if
|
||||||
// outcomeOp.toSystem has already called outcomeStateSys.instance.
|
// outcomeOp.toSystem has already called outcomeStateSys.instance.
|
||||||
func (s *outcomeState) instancePath() *check.Absolute {
|
func (s *outcomeState) instancePath() *check.Absolute { return s.sc.SharePath.Append(s.id.String()) }
|
||||||
return s.sc.SharePath.Append(s.id.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// runtimePath returns a path formatted for outcomeStateSys.runtime.
|
// runtimePath returns a path formatted for outcomeStateSys.runtime.
|
||||||
//
|
|
||||||
// This method must only be called from outcomeOp.toContainer if
|
// This method must only be called from outcomeOp.toContainer if
|
||||||
// outcomeOp.toSystem has already called outcomeStateSys.runtime.
|
// outcomeOp.toSystem has already called outcomeStateSys.runtime.
|
||||||
func (s *outcomeState) runtimePath() *check.Absolute {
|
func (s *outcomeState) runtimePath() *check.Absolute { return s.sc.RunDirPath.Append(s.id.String()) }
|
||||||
return s.sc.RunDirPath.Append(s.id.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// outcomeStateSys wraps outcomeState and [system.I]. Used on the priv side only.
|
// outcomeStateSys wraps outcomeState and [system.I]. Used on the priv side only.
|
||||||
//
|
// Implementations of outcomeOp must not access fields other than sys unless explicitly stated.
|
||||||
// Implementations of outcomeOp must not access fields other than sys unless
|
|
||||||
// explicitly stated.
|
|
||||||
type outcomeStateSys struct {
|
type outcomeStateSys struct {
|
||||||
// Whether XDG_RUNTIME_DIR is used post hsu.
|
// Whether XDG_RUNTIME_DIR is used post hsu.
|
||||||
useRuntimeDir bool
|
useRuntimeDir bool
|
||||||
@@ -245,7 +219,6 @@ func (state *outcomeStateSys) ensureRuntimeDir() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// instance returns the pathname to a process-specific directory within TMPDIR.
|
// instance returns the pathname to a process-specific directory within TMPDIR.
|
||||||
//
|
|
||||||
// This directory must only hold entries bound to [system.Process].
|
// This directory must only hold entries bound to [system.Process].
|
||||||
func (state *outcomeStateSys) instance() *check.Absolute {
|
func (state *outcomeStateSys) instance() *check.Absolute {
|
||||||
if state.sharePath != nil {
|
if state.sharePath != nil {
|
||||||
@@ -257,7 +230,6 @@ func (state *outcomeStateSys) instance() *check.Absolute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// runtime returns the pathname to a process-specific directory within XDG_RUNTIME_DIR.
|
// runtime returns the pathname to a process-specific directory within XDG_RUNTIME_DIR.
|
||||||
//
|
|
||||||
// This directory must only hold entries bound to [system.Process].
|
// This directory must only hold entries bound to [system.Process].
|
||||||
func (state *outcomeStateSys) runtime() *check.Absolute {
|
func (state *outcomeStateSys) runtime() *check.Absolute {
|
||||||
if state.runtimeSharePath != nil {
|
if state.runtimeSharePath != nil {
|
||||||
@@ -270,29 +242,22 @@ func (state *outcomeStateSys) runtime() *check.Absolute {
|
|||||||
return state.runtimeSharePath
|
return state.runtimeSharePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// outcomeStateParams wraps outcomeState and [container.Params].
|
// outcomeStateParams wraps outcomeState and [container.Params]. Used on the shim side only.
|
||||||
//
|
|
||||||
// Used on the shim side only.
|
|
||||||
type outcomeStateParams struct {
|
type outcomeStateParams struct {
|
||||||
// Overrides the embedded [container.Params] in [container.Container].
|
// Overrides the embedded [container.Params] in [container.Container]. The Env field must not be used.
|
||||||
//
|
|
||||||
// The Env field must not be used.
|
|
||||||
params *container.Params
|
params *container.Params
|
||||||
// Collapsed into the Env slice in [container.Params] by the final outcomeOp.
|
// Collapsed into the Env slice in [container.Params] by the final outcomeOp.
|
||||||
env map[string]string
|
env map[string]string
|
||||||
|
|
||||||
// Filesystems with the optional root sliced off if present.
|
// Filesystems with the optional root sliced off if present. Populated by spParamsOp.
|
||||||
//
|
// Safe for use by spFilesystemOp.
|
||||||
// Populated by spParamsOp. Safe for use by spFilesystemOp.
|
|
||||||
filesystem []hst.FilesystemConfigJSON
|
filesystem []hst.FilesystemConfigJSON
|
||||||
|
|
||||||
// Inner XDG_RUNTIME_DIR default formatting of `/run/user/%d` via mapped uid.
|
// Inner XDG_RUNTIME_DIR default formatting of `/run/user/%d` via mapped uid.
|
||||||
//
|
|
||||||
// Populated by spRuntimeOp.
|
// Populated by spRuntimeOp.
|
||||||
runtimeDir *check.Absolute
|
runtimeDir *check.Absolute
|
||||||
|
|
||||||
// Path to pipewire-pulse server.
|
// Path to pipewire-pulse server.
|
||||||
//
|
|
||||||
// Populated by spPipeWireOp if DirectPipeWire is false.
|
// Populated by spPipeWireOp if DirectPipeWire is false.
|
||||||
pipewirePulsePath *check.Absolute
|
pipewirePulsePath *check.Absolute
|
||||||
|
|
||||||
@@ -300,32 +265,25 @@ type outcomeStateParams struct {
|
|||||||
*outcomeState
|
*outcomeState
|
||||||
}
|
}
|
||||||
|
|
||||||
// errNotEnabled is returned by outcomeOp.toSystem and used internally to
|
// errNotEnabled is returned by outcomeOp.toSystem and used internally to exclude an outcomeOp from transmission.
|
||||||
// exclude an outcomeOp from transmission.
|
|
||||||
var errNotEnabled = errors.New("op not enabled in the configuration")
|
var errNotEnabled = errors.New("op not enabled in the configuration")
|
||||||
|
|
||||||
// An outcomeOp inflicts an outcome on [system.I] and contains enough
|
// An outcomeOp inflicts an outcome on [system.I] and contains enough information to
|
||||||
// information to inflict it on [container.Params] in a separate process.
|
// inflict it on [container.Params] in a separate process.
|
||||||
//
|
// An implementation of outcomeOp must store cross-process states in exported fields only.
|
||||||
// An implementation of outcomeOp must store cross-process states in exported
|
|
||||||
// fields only.
|
|
||||||
type outcomeOp interface {
|
type outcomeOp interface {
|
||||||
// toSystem inflicts the current outcome on [system.I] in the priv side process.
|
// toSystem inflicts the current outcome on [system.I] in the priv side process.
|
||||||
toSystem(state *outcomeStateSys) error
|
toSystem(state *outcomeStateSys) error
|
||||||
|
|
||||||
// toContainer inflicts the current outcome on [container.Params] in the
|
// toContainer inflicts the current outcome on [container.Params] in the shim process.
|
||||||
// shim process.
|
// The implementation must not write to the Env field of [container.Params] as it will be overwritten
|
||||||
//
|
// by flattened env map.
|
||||||
// Implementations must not write to the Env field of [container.Params]
|
|
||||||
// as it will be overwritten by flattened env map.
|
|
||||||
toContainer(state *outcomeStateParams) error
|
toContainer(state *outcomeStateParams) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// toSystem calls the outcomeOp.toSystem method on all outcomeOp implementations
|
// toSystem calls the outcomeOp.toSystem method on all outcomeOp implementations and populates shimParams.Ops.
|
||||||
// and populates shimParams.Ops.
|
// This function assumes the caller has already called the Validate method on [hst.Config]
|
||||||
//
|
// and checked that it returns nil.
|
||||||
// This function assumes the caller has already called the Validate method on
|
|
||||||
// [hst.Config] and checked that it returns nil.
|
|
||||||
func (state *outcomeStateSys) toSystem() error {
|
func (state *outcomeStateSys) toSystem() error {
|
||||||
if state.Shim == nil || state.Shim.Ops != nil {
|
if state.Shim == nil || state.Shim.Ops != nil {
|
||||||
return newWithMessage("invalid ops state reached")
|
return newWithMessage("invalid ops state reached")
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewStore returns the address of a new instance of [store.Store].
|
// NewStore returns the address of a new instance of [store.Store].
|
||||||
func NewStore(sc *hst.Paths) *store.Store {
|
func NewStore(sc *hst.Paths) *store.Store { return store.New(sc.SharePath.Append("state")) }
|
||||||
return store.New(sc.SharePath.Append("state"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// main carries out outcome and terminates. main does not return.
|
// main carries out outcome and terminates. main does not return.
|
||||||
func (k *outcome) main(msg message.Msg, identifierFd int) {
|
func (k *outcome) main(msg message.Msg, identifierFd int) {
|
||||||
@@ -118,11 +116,7 @@ func (k *outcome) main(msg message.Msg, identifierFd int) {
|
|||||||
processStatePrev, processStateCur = processStateCur, processState
|
processStatePrev, processStateCur = processStateCur, processState
|
||||||
|
|
||||||
if !processTime.IsZero() && processStatePrev != processLifecycle {
|
if !processTime.IsZero() && processStatePrev != processLifecycle {
|
||||||
msg.Verbosef(
|
msg.Verbosef("state %d took %.2f ms", processStatePrev, float64(time.Since(processTime).Nanoseconds())/1e6)
|
||||||
"state %d took %.2f ms",
|
|
||||||
processStatePrev,
|
|
||||||
float64(time.Since(processTime).Nanoseconds())/1e6,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
processTime = time.Now()
|
processTime = time.Now()
|
||||||
|
|
||||||
@@ -147,10 +141,7 @@ func (k *outcome) main(msg message.Msg, identifierFd int) {
|
|||||||
|
|
||||||
case processCommit:
|
case processCommit:
|
||||||
if isBeforeRevert {
|
if isBeforeRevert {
|
||||||
perrorFatal(
|
perrorFatal(newWithMessage("invalid transition to commit state"), "commit", processLifecycle)
|
||||||
newWithMessage("invalid transition to commit state"),
|
|
||||||
"commit", processLifecycle,
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,26 +238,15 @@ func (k *outcome) main(msg message.Msg, identifierFd int) {
|
|||||||
|
|
||||||
case <-func() chan struct{} {
|
case <-func() chan struct{} {
|
||||||
w := make(chan struct{})
|
w := make(chan struct{})
|
||||||
// This ties processLifecycle to ctx with the additional
|
// this ties processLifecycle to ctx with the additional compensated timeout duration
|
||||||
// compensated timeout duration to allow transition to the next
|
// to allow transition to the next state on a locked up shim
|
||||||
// state on a locked up shim.
|
go func() { <-ctx.Done(); time.Sleep(k.state.Shim.WaitDelay + shimWaitTimeout); close(w) }()
|
||||||
go func() {
|
|
||||||
<-ctx.Done()
|
|
||||||
time.Sleep(k.state.Shim.WaitDelay + shimWaitTimeout)
|
|
||||||
close(w)
|
|
||||||
}()
|
|
||||||
return w
|
return w
|
||||||
}():
|
}():
|
||||||
// This is only reachable when wait did not return within
|
// this is only reachable when wait did not return within shimWaitTimeout, after its WaitDelay has elapsed.
|
||||||
// shimWaitTimeout, after its WaitDelay has elapsed. This is
|
// This is different from the container failing to terminate within its timeout period, as that is enforced
|
||||||
// different from the container failing to terminate within its
|
// by the shim. This path is instead reached when there is a lockup in shim preventing it from completing.
|
||||||
// timeout period, as that is enforced by the shim. This path is
|
msg.GetLogger().Printf("process %d did not terminate", shimCmd.Process.Pid)
|
||||||
// instead reached when there is a lockup in shim preventing it
|
|
||||||
// from completing.
|
|
||||||
msg.GetLogger().Printf(
|
|
||||||
"process %d did not terminate",
|
|
||||||
shimCmd.Process.Pid,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
msg.Resume()
|
msg.Resume()
|
||||||
|
|
||||||
@@ -291,8 +271,8 @@ func (k *outcome) main(msg message.Msg, identifierFd int) {
|
|||||||
ec := system.Process
|
ec := system.Process
|
||||||
|
|
||||||
if entries, _, err := handle.Entries(); err != nil {
|
if entries, _, err := handle.Entries(); err != nil {
|
||||||
// it is impossible to continue from this point, per-process
|
// it is impossible to continue from this point,
|
||||||
// state will be reverted to limit damage
|
// per-process state will be reverted to limit damage
|
||||||
perror(err, "read store segment entries")
|
perror(err, "read store segment entries")
|
||||||
} else {
|
} else {
|
||||||
// accumulate enablements of remaining instances
|
// accumulate enablements of remaining instances
|
||||||
@@ -315,10 +295,7 @@ func (k *outcome) main(msg message.Msg, identifierFd int) {
|
|||||||
if n == 0 {
|
if n == 0 {
|
||||||
ec |= system.User
|
ec |= system.User
|
||||||
} else {
|
} else {
|
||||||
msg.Verbosef(
|
msg.Verbosef("found %d instances, cleaning up without user-scoped operations", n)
|
||||||
"found %d instances, cleaning up without user-scoped operations",
|
|
||||||
n,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ec |= rt ^ (hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse)
|
ec |= rt ^ (hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse)
|
||||||
if msg.IsVerbose() {
|
if msg.IsVerbose() {
|
||||||
@@ -358,9 +335,7 @@ func (k *outcome) main(msg message.Msg, identifierFd int) {
|
|||||||
|
|
||||||
// start starts the shim via cmd/hsu.
|
// start starts the shim via cmd/hsu.
|
||||||
//
|
//
|
||||||
// If successful, a [time.Time] value for [hst.State] is stored in the value
|
// If successful, a [time.Time] value for [hst.State] is stored in the value pointed to by startTime.
|
||||||
// pointed to by startTime.
|
|
||||||
//
|
|
||||||
// The resulting [exec.Cmd] and write end of the shim setup pipe is returned.
|
// The resulting [exec.Cmd] and write end of the shim setup pipe is returned.
|
||||||
func (k *outcome) start(ctx context.Context, msg message.Msg,
|
func (k *outcome) start(ctx context.Context, msg message.Msg,
|
||||||
hsuPath *check.Absolute,
|
hsuPath *check.Absolute,
|
||||||
|
|||||||
@@ -37,12 +37,9 @@ const (
|
|||||||
shimMsgBadPID = C.HAKUREI_SHIM_BAD_PID
|
shimMsgBadPID = C.HAKUREI_SHIM_BAD_PID
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupContSignal sets up the SIGCONT signal handler for the cross-uid shim
|
// setupContSignal sets up the SIGCONT signal handler for the cross-uid shim exit hack.
|
||||||
// exit hack.
|
// The signal handler is implemented in C, signals can be processed by reading from the returned reader.
|
||||||
//
|
// The returned function must be called after all signal processing concludes.
|
||||||
// The signal handler is implemented in C, signals can be processed by reading
|
|
||||||
// from the returned reader. The returned function must be called after all
|
|
||||||
// signal processing concludes.
|
|
||||||
func setupContSignal(pid int) (io.ReadCloser, func(), error) {
|
func setupContSignal(pid int) (io.ReadCloser, func(), error) {
|
||||||
if r, w, err := os.Pipe(); err != nil {
|
if r, w, err := os.Pipe(); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -54,30 +51,22 @@ func setupContSignal(pid int) (io.ReadCloser, func(), error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shimEnv is the name of the environment variable storing decimal representation
|
// shimEnv is the name of the environment variable storing decimal representation of
|
||||||
// of setup pipe fd for [container.Receive].
|
// setup pipe fd for [container.Receive].
|
||||||
const shimEnv = "HAKUREI_SHIM"
|
const shimEnv = "HAKUREI_SHIM"
|
||||||
|
|
||||||
// shimParams is embedded in outcomeState and transmitted from priv side to shim.
|
// shimParams is embedded in outcomeState and transmitted from priv side to shim.
|
||||||
type shimParams struct {
|
type shimParams struct {
|
||||||
// Priv side pid, checked against ppid in signal handler for the
|
// Priv side pid, checked against ppid in signal handler for the syscall.SIGCONT hack.
|
||||||
// syscall.SIGCONT hack.
|
|
||||||
PrivPID int
|
PrivPID int
|
||||||
|
|
||||||
// Duration to wait for after the initial process receives os.Interrupt
|
// Duration to wait for after the initial process receives os.Interrupt before the container is killed.
|
||||||
// before the container is killed.
|
|
||||||
//
|
|
||||||
// Limits are enforced on the priv side.
|
// Limits are enforced on the priv side.
|
||||||
WaitDelay time.Duration
|
WaitDelay time.Duration
|
||||||
|
|
||||||
// Verbosity pass through from [message.Msg].
|
// Verbosity pass through from [message.Msg].
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
|
||||||
// Copied from [hst.Config].
|
|
||||||
SchedPolicy std.SchedPolicy
|
|
||||||
// Copied from [hst.Config].
|
|
||||||
SchedPriority std.Int
|
|
||||||
|
|
||||||
// Outcome setup ops, contains setup state. Populated by outcome.finalise.
|
// Outcome setup ops, contains setup state. Populated by outcome.finalise.
|
||||||
Ops []outcomeOp
|
Ops []outcomeOp
|
||||||
}
|
}
|
||||||
@@ -88,9 +77,7 @@ func (p *shimParams) valid() bool { return p != nil && p.PrivPID > 0 }
|
|||||||
// shimName is the prefix used by log.std in the shim process.
|
// shimName is the prefix used by log.std in the shim process.
|
||||||
const shimName = "shim"
|
const shimName = "shim"
|
||||||
|
|
||||||
// Shim is called by the main function of the shim process and runs as the
|
// Shim is called by the main function of the shim process and runs as the unconstrained target user.
|
||||||
// unconstrained target user.
|
|
||||||
//
|
|
||||||
// Shim does not return.
|
// Shim does not return.
|
||||||
func Shim(msg message.Msg) {
|
func Shim(msg message.Msg) {
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
@@ -144,8 +131,7 @@ func (sp *shimPrivate) destroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// shimPipeWireTimeout is the duration pipewire-pulse is allowed to run
|
// shimPipeWireTimeout is the duration pipewire-pulse is allowed to run before its socket becomes available.
|
||||||
// before its socket becomes available.
|
|
||||||
shimPipeWireTimeout = 5 * time.Second
|
shimPipeWireTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -276,9 +262,6 @@ func shimEntrypoint(k syscallDispatcher) {
|
|||||||
cancelContainer.Store(&stop)
|
cancelContainer.Store(&stop)
|
||||||
sp := shimPrivate{k: k, id: state.id}
|
sp := shimPrivate{k: k, id: state.id}
|
||||||
z := container.New(ctx, msg)
|
z := container.New(ctx, msg)
|
||||||
z.SetScheduler = state.Shim.SchedPolicy > 0
|
|
||||||
z.SchedPolicy = state.Shim.SchedPolicy
|
|
||||||
z.SchedPriority = state.Shim.SchedPriority
|
|
||||||
z.Params = *stateParams.params
|
z.Params = *stateParams.params
|
||||||
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
|
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ const varRunNscd = fhs.Var + "run/nscd"
|
|||||||
|
|
||||||
func init() { gob.Register(new(spParamsOp)) }
|
func init() { gob.Register(new(spParamsOp)) }
|
||||||
|
|
||||||
// spParamsOp initialises unordered fields of [container.Params] and the
|
// spParamsOp initialises unordered fields of [container.Params] and the optional root filesystem.
|
||||||
// optional root filesystem.
|
|
||||||
//
|
|
||||||
// This outcomeOp is hardcoded to always run first.
|
// This outcomeOp is hardcoded to always run first.
|
||||||
type spParamsOp struct {
|
type spParamsOp struct {
|
||||||
// Value of $TERM, stored during toSystem.
|
// Value of $TERM, stored during toSystem.
|
||||||
@@ -69,8 +67,8 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error {
|
|||||||
state.params.Args = state.Container.Args
|
state.params.Args = state.Container.Args
|
||||||
}
|
}
|
||||||
|
|
||||||
// The container is cancelled when shim is requested to exit or receives an
|
// the container is canceled when shim is requested to exit or receives an interrupt or termination signal;
|
||||||
// interrupt or termination signal. This behaviour is implemented in the shim.
|
// this behaviour is implemented in the shim
|
||||||
state.params.ForwardCancel = state.Shim.WaitDelay > 0
|
state.params.ForwardCancel = state.Shim.WaitDelay > 0
|
||||||
|
|
||||||
if state.Container.Flags&hst.FMultiarch != 0 {
|
if state.Container.Flags&hst.FMultiarch != 0 {
|
||||||
@@ -117,8 +115,7 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error {
|
|||||||
} else {
|
} else {
|
||||||
state.params.Bind(fhs.AbsDev, fhs.AbsDev, std.BindWritable|std.BindDevice)
|
state.params.Bind(fhs.AbsDev, fhs.AbsDev, std.BindWritable|std.BindDevice)
|
||||||
}
|
}
|
||||||
// /dev is mounted readonly later on, this prevents /dev/shm from going
|
// /dev is mounted readonly later on, this prevents /dev/shm from going readonly with it
|
||||||
// readonly with it
|
|
||||||
state.params.Tmpfs(fhs.AbsDevShm, 0, 01777)
|
state.params.Tmpfs(fhs.AbsDevShm, 0, 01777)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -126,9 +123,7 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error {
|
|||||||
|
|
||||||
func init() { gob.Register(new(spFilesystemOp)) }
|
func init() { gob.Register(new(spFilesystemOp)) }
|
||||||
|
|
||||||
// spFilesystemOp applies configured filesystems to [container.Params],
|
// spFilesystemOp applies configured filesystems to [container.Params], excluding the optional root filesystem.
|
||||||
// excluding the optional root filesystem.
|
|
||||||
//
|
|
||||||
// This outcomeOp is hardcoded to always run last.
|
// This outcomeOp is hardcoded to always run last.
|
||||||
type spFilesystemOp struct {
|
type spFilesystemOp struct {
|
||||||
// Matched paths to cover. Stored during toSystem.
|
// Matched paths to cover. Stored during toSystem.
|
||||||
@@ -302,8 +297,8 @@ func (s *spFilesystemOp) toContainer(state *outcomeStateParams) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveRoot handles the root filesystem special case for [hst.FilesystemConfig]
|
// resolveRoot handles the root filesystem special case for [hst.FilesystemConfig] and additionally resolves autoroot
|
||||||
// and additionally resolves autoroot as it requires special handling during path hiding.
|
// as it requires special handling during path hiding.
|
||||||
func resolveRoot(c *hst.ContainerConfig) (rootfs hst.FilesystemConfig, filesystem []hst.FilesystemConfigJSON, autoroot *hst.FSBind) {
|
func resolveRoot(c *hst.ContainerConfig) (rootfs hst.FilesystemConfig, filesystem []hst.FilesystemConfigJSON, autoroot *hst.FSBind) {
|
||||||
// root filesystem special case
|
// root filesystem special case
|
||||||
filesystem = c.Filesystem
|
filesystem = c.Filesystem
|
||||||
@@ -321,8 +316,7 @@ func resolveRoot(c *hst.ContainerConfig) (rootfs hst.FilesystemConfig, filesyste
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// evalSymlinks calls syscallDispatcher.evalSymlinks but discards errors
|
// evalSymlinks calls syscallDispatcher.evalSymlinks but discards errors unwrapping to [fs.ErrNotExist].
|
||||||
// unwrapping to [fs.ErrNotExist].
|
|
||||||
func evalSymlinks(msg message.Msg, k syscallDispatcher, v *string) error {
|
func evalSymlinks(msg message.Msg, k syscallDispatcher, v *string) error {
|
||||||
if p, err := k.evalSymlinks(*v); err != nil {
|
if p, err := k.evalSymlinks(*v); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
func init() { gob.Register(new(spDBusOp)) }
|
func init() { gob.Register(new(spDBusOp)) }
|
||||||
|
|
||||||
// spDBusOp maintains an xdg-dbus-proxy instance for the container.
|
// spDBusOp maintains an xdg-dbus-proxy instance for the container.
|
||||||
//
|
|
||||||
// Runs after spRuntimeOp.
|
// Runs after spRuntimeOp.
|
||||||
type spDBusOp struct {
|
type spDBusOp struct {
|
||||||
// Whether to bind the system bus socket. Populated during toSystem.
|
// Whether to bind the system bus socket. Populated during toSystem.
|
||||||
|
|||||||
@@ -13,12 +13,9 @@ const pipewirePulseName = "pipewire-pulse"
|
|||||||
func init() { gob.Register(new(spPipeWireOp)) }
|
func init() { gob.Register(new(spPipeWireOp)) }
|
||||||
|
|
||||||
// spPipeWireOp exports the PipeWire server to the container via SecurityContext.
|
// spPipeWireOp exports the PipeWire server to the container via SecurityContext.
|
||||||
//
|
|
||||||
// Runs after spRuntimeOp.
|
// Runs after spRuntimeOp.
|
||||||
type spPipeWireOp struct {
|
type spPipeWireOp struct {
|
||||||
// Path to pipewire-pulse server.
|
// Path to pipewire-pulse server. Populated during toSystem if DirectPipeWire is false.
|
||||||
//
|
|
||||||
// Populated during toSystem if DirectPipeWire is false.
|
|
||||||
CompatServerPath *check.Absolute
|
CompatServerPath *check.Absolute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ const pulseCookieSizeMax = 1 << 8
|
|||||||
func init() { gob.Register(new(spPulseOp)) }
|
func init() { gob.Register(new(spPulseOp)) }
|
||||||
|
|
||||||
// spPulseOp exports the PulseAudio server to the container.
|
// spPulseOp exports the PulseAudio server to the container.
|
||||||
//
|
|
||||||
// Runs after spRuntimeOp.
|
// Runs after spRuntimeOp.
|
||||||
type spPulseOp struct {
|
type spPulseOp struct {
|
||||||
// PulseAudio cookie data, populated during toSystem if a cookie is present.
|
// PulseAudio cookie data, populated during toSystem if a cookie is present.
|
||||||
@@ -38,40 +37,24 @@ func (s *spPulseOp) toSystem(state *outcomeStateSys) error {
|
|||||||
|
|
||||||
if _, err := state.k.stat(pulseRuntimeDir.String()); err != nil {
|
if _, err := state.k.stat(pulseRuntimeDir.String()); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return &hst.AppError{Step: fmt.Sprintf(
|
return &hst.AppError{Step: fmt.Sprintf("access PulseAudio directory %q", pulseRuntimeDir), Err: err}
|
||||||
"access PulseAudio directory %q",
|
|
||||||
pulseRuntimeDir,
|
|
||||||
), Err: err}
|
|
||||||
}
|
}
|
||||||
return newWithMessageError(fmt.Sprintf(
|
return newWithMessageError(fmt.Sprintf("PulseAudio directory %q not found", pulseRuntimeDir), err)
|
||||||
"PulseAudio directory %q not found",
|
|
||||||
pulseRuntimeDir,
|
|
||||||
), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi, err := state.k.stat(pulseSocket.String()); err != nil {
|
if fi, err := state.k.stat(pulseSocket.String()); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return &hst.AppError{Step: fmt.Sprintf(
|
return &hst.AppError{Step: fmt.Sprintf("access PulseAudio socket %q", pulseSocket), Err: err}
|
||||||
"access PulseAudio socket %q",
|
|
||||||
pulseSocket,
|
|
||||||
), Err: err}
|
|
||||||
}
|
}
|
||||||
return newWithMessageError(fmt.Sprintf(
|
return newWithMessageError(fmt.Sprintf("PulseAudio directory %q found but socket does not exist", pulseRuntimeDir), err)
|
||||||
"PulseAudio directory %q found but socket does not exist",
|
|
||||||
pulseRuntimeDir,
|
|
||||||
), err)
|
|
||||||
} else {
|
} else {
|
||||||
if m := fi.Mode(); m&0o006 != 0o006 {
|
if m := fi.Mode(); m&0o006 != 0o006 {
|
||||||
return newWithMessage(fmt.Sprintf(
|
return newWithMessage(fmt.Sprintf("unexpected permissions on %q: %s", pulseSocket, m))
|
||||||
"unexpected permissions on %q: %s",
|
|
||||||
pulseSocket, m,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PulseAudio socket is world writable and its parent directory DAC
|
// pulse socket is world writable and its parent directory DAC permissions prevents access;
|
||||||
// permissions prevents access. Hard link to target-executable share
|
// hard link to target-executable share directory to grant access
|
||||||
// directory to grant access
|
|
||||||
state.sys.Link(pulseSocket, state.runtime().Append("pulse"))
|
state.sys.Link(pulseSocket, state.runtime().Append("pulse"))
|
||||||
|
|
||||||
// load up to pulseCookieSizeMax bytes of pulse cookie for transmission to shim
|
// load up to pulseCookieSizeMax bytes of pulse cookie for transmission to shim
|
||||||
@@ -79,13 +62,7 @@ func (s *spPulseOp) toSystem(state *outcomeStateSys) error {
|
|||||||
return err
|
return err
|
||||||
} else if a != nil {
|
} else if a != nil {
|
||||||
s.Cookie = new([pulseCookieSizeMax]byte)
|
s.Cookie = new([pulseCookieSizeMax]byte)
|
||||||
if s.CookieSize, err = loadFile(
|
if s.CookieSize, err = loadFile(state.msg, state.k, "PulseAudio cookie", a.String(), s.Cookie[:]); err != nil {
|
||||||
state.msg,
|
|
||||||
state.k,
|
|
||||||
"PulseAudio cookie",
|
|
||||||
a.String(),
|
|
||||||
s.Cookie[:],
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -124,9 +101,8 @@ func (s *spPulseOp) commonPaths(state *outcomeState) (pulseRuntimeDir, pulseSock
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// discoverPulseCookie attempts to discover the pathname of the PulseAudio
|
// discoverPulseCookie attempts to discover the pathname of the PulseAudio cookie of the current user.
|
||||||
// cookie of the current user. If both returned pathname and error are nil, the
|
// If both returned pathname and error are nil, the cookie is likely unavailable and can be silently skipped.
|
||||||
// cookie is likely unavailable and can be silently skipped.
|
|
||||||
func discoverPulseCookie(k syscallDispatcher) (*check.Absolute, error) {
|
func discoverPulseCookie(k syscallDispatcher) (*check.Absolute, error) {
|
||||||
const paLocateStep = "locate PulseAudio cookie"
|
const paLocateStep = "locate PulseAudio cookie"
|
||||||
|
|
||||||
@@ -210,10 +186,7 @@ func loadFile(
|
|||||||
&os.PathError{Op: "stat", Path: pathname, Err: syscall.ENOMEM},
|
&os.PathError{Op: "stat", Path: pathname, Err: syscall.ENOMEM},
|
||||||
)
|
)
|
||||||
} else if s < int64(n) {
|
} else if s < int64(n) {
|
||||||
msg.Verbosef(
|
msg.Verbosef("%s at %q is %d bytes shorter than expected", description, pathname, int64(n)-s)
|
||||||
"%s at %q is %d bytes shorter than expected",
|
|
||||||
description, pathname, int64(n)-s,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
msg.Verbosef("loading %d bytes from %q", n, pathname)
|
msg.Verbosef("loading %d bytes from %q", n, pathname)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,9 +67,7 @@ const (
|
|||||||
|
|
||||||
// spRuntimeOp sets up XDG_RUNTIME_DIR inside the container.
|
// spRuntimeOp sets up XDG_RUNTIME_DIR inside the container.
|
||||||
type spRuntimeOp struct {
|
type spRuntimeOp struct {
|
||||||
// SessionType determines the value of envXDGSessionType.
|
// SessionType determines the value of envXDGSessionType. Populated during toSystem.
|
||||||
//
|
|
||||||
// Populated during toSystem.
|
|
||||||
SessionType uintptr
|
SessionType uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,9 @@ import (
|
|||||||
func init() { gob.Register(new(spWaylandOp)) }
|
func init() { gob.Register(new(spWaylandOp)) }
|
||||||
|
|
||||||
// spWaylandOp exports the Wayland display server to the container.
|
// spWaylandOp exports the Wayland display server to the container.
|
||||||
//
|
|
||||||
// Runs after spRuntimeOp.
|
// Runs after spRuntimeOp.
|
||||||
type spWaylandOp struct {
|
type spWaylandOp struct {
|
||||||
// Path to host wayland socket.
|
// Path to host wayland socket. Populated during toSystem if DirectWayland is true.
|
||||||
//
|
|
||||||
// Populated during toSystem if DirectWayland is true.
|
|
||||||
SocketPath *check.Absolute
|
SocketPath *check.Absolute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ func (s *spX11Op) toSystem(state *outcomeStateSys) error {
|
|||||||
if socketPath != nil {
|
if socketPath != nil {
|
||||||
if _, err := state.k.stat(socketPath.String()); err != nil {
|
if _, err := state.k.stat(socketPath.String()); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return &hst.AppError{Step: fmt.Sprintf(
|
return &hst.AppError{Step: fmt.Sprintf("access X11 socket %q", socketPath), Err: err}
|
||||||
"access X11 socket %q",
|
|
||||||
socketPath,
|
|
||||||
), Err: err}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.sys.UpdatePermType(hst.EX11, socketPath, acl.Read, acl.Write, acl.Execute)
|
state.sys.UpdatePermType(hst.EX11, socketPath, acl.Read, acl.Write, acl.Execute)
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ type ExecPath struct {
|
|||||||
W bool
|
W bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSchedIdle is whether to set [std.SCHED_IDLE] scheduling priority.
|
// SchedPolicy is the [container] scheduling policy.
|
||||||
var SetSchedIdle bool
|
var SchedPolicy int
|
||||||
|
|
||||||
// PromoteLayers returns artifacts with identical-by-content layers promoted to
|
// PromoteLayers returns artifacts with identical-by-content layers promoted to
|
||||||
// the highest priority instance, as if mounted via [ExecPath].
|
// the highest priority instance, as if mounted via [ExecPath].
|
||||||
@@ -413,8 +413,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
z.ParentPerm = 0700
|
z.ParentPerm = 0700
|
||||||
z.HostNet = hostNet
|
z.HostNet = hostNet
|
||||||
z.Hostname = "cure"
|
z.Hostname = "cure"
|
||||||
z.SetScheduler = SetSchedIdle
|
z.SchedPolicy = SchedPolicy
|
||||||
z.SchedPolicy = std.SCHED_IDLE
|
|
||||||
if z.HostNet {
|
if z.HostNet {
|
||||||
z.Hostname = "cure-net"
|
z.Hostname = "cure-net"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,10 +101,6 @@ func init() {
|
|||||||
Description: "Commands for Manipulating POSIX Access Control Lists",
|
Description: "Commands for Manipulating POSIX Access Control Lists",
|
||||||
Website: "https://savannah.nongnu.org/projects/acl/",
|
Website: "https://savannah.nongnu.org/projects/acl/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Attr,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 16,
|
ID: 16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -20,10 +19,8 @@ const (
|
|||||||
LLVMRuntimes
|
LLVMRuntimes
|
||||||
LLVMClang
|
LLVMClang
|
||||||
|
|
||||||
// EarlyInit is the Rosa OS init program.
|
// EarlyInit is the Rosa OS initramfs init program.
|
||||||
EarlyInit
|
EarlyInit
|
||||||
// ImageSystem is the Rosa OS /system image.
|
|
||||||
ImageSystem
|
|
||||||
// ImageInitramfs is the Rosa OS initramfs archive.
|
// ImageInitramfs is the Rosa OS initramfs archive.
|
||||||
ImageInitramfs
|
ImageInitramfs
|
||||||
|
|
||||||
@@ -170,36 +167,6 @@ const (
|
|||||||
PresetEnd
|
PresetEnd
|
||||||
)
|
)
|
||||||
|
|
||||||
// P represents multiple [PArtifact] and is stable through JSON.
|
|
||||||
type P []PArtifact
|
|
||||||
|
|
||||||
// MarshalJSON represents [PArtifact] by their [Metadata.Name].
|
|
||||||
func (s P) MarshalJSON() ([]byte, error) {
|
|
||||||
names := make([]string, len(s))
|
|
||||||
for i, p := range s {
|
|
||||||
names[i] = GetMetadata(p).Name
|
|
||||||
}
|
|
||||||
return json.Marshal(names)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON resolves the value created by MarshalJSON back to [P].
|
|
||||||
func (s *P) UnmarshalJSON(data []byte) error {
|
|
||||||
var names []string
|
|
||||||
if err := json.Unmarshal(data, &names); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*s = make(P, len(names))
|
|
||||||
for i, name := range names {
|
|
||||||
if p, ok := ResolveName(name); !ok {
|
|
||||||
return fmt.Errorf("unknown artifact %q", name)
|
|
||||||
} else {
|
|
||||||
(*s)[i] = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metadata is stage-agnostic information of a [PArtifact] not directly
|
// Metadata is stage-agnostic information of a [PArtifact] not directly
|
||||||
// representable in the resulting [pkg.Artifact].
|
// representable in the resulting [pkg.Artifact].
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
@@ -212,9 +179,6 @@ type Metadata struct {
|
|||||||
// Project home page.
|
// Project home page.
|
||||||
Website string `json:"website,omitempty"`
|
Website string `json:"website,omitempty"`
|
||||||
|
|
||||||
// Runtime dependencies.
|
|
||||||
Dependencies P `json:"dependencies"`
|
|
||||||
|
|
||||||
// Project identifier on [Anitya].
|
// Project identifier on [Anitya].
|
||||||
//
|
//
|
||||||
// [Anitya]: https://release-monitoring.org/
|
// [Anitya]: https://release-monitoring.org/
|
||||||
@@ -292,10 +256,9 @@ var (
|
|||||||
artifactsM [PresetEnd]Metadata
|
artifactsM [PresetEnd]Metadata
|
||||||
|
|
||||||
// artifacts stores the result of Metadata.f.
|
// artifacts stores the result of Metadata.f.
|
||||||
artifacts [_toolchainEnd][len(artifactsM)]struct {
|
artifacts [_toolchainEnd][len(artifactsM)]pkg.Artifact
|
||||||
a pkg.Artifact
|
// versions stores the version of [PArtifact].
|
||||||
v string
|
versions [_toolchainEnd][len(artifactsM)]string
|
||||||
}
|
|
||||||
// artifactsOnce is for lazy initialisation of artifacts.
|
// artifactsOnce is for lazy initialisation of artifacts.
|
||||||
artifactsOnce [_toolchainEnd][len(artifactsM)]sync.Once
|
artifactsOnce [_toolchainEnd][len(artifactsM)]sync.Once
|
||||||
)
|
)
|
||||||
@@ -303,23 +266,20 @@ var (
|
|||||||
// GetMetadata returns [Metadata] of a [PArtifact].
|
// GetMetadata returns [Metadata] of a [PArtifact].
|
||||||
func GetMetadata(p PArtifact) *Metadata { return &artifactsM[p] }
|
func GetMetadata(p PArtifact) *Metadata { return &artifactsM[p] }
|
||||||
|
|
||||||
// construct constructs a [pkg.Artifact] corresponding to a [PArtifact] once.
|
|
||||||
func (t Toolchain) construct(p PArtifact) {
|
|
||||||
artifactsOnce[t][p].Do(func() {
|
|
||||||
artifacts[t][p].a, artifacts[t][p].v = artifactsM[p].f(t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load returns the resulting [pkg.Artifact] of [PArtifact].
|
// Load returns the resulting [pkg.Artifact] of [PArtifact].
|
||||||
func (t Toolchain) Load(p PArtifact) pkg.Artifact {
|
func (t Toolchain) Load(p PArtifact) pkg.Artifact {
|
||||||
t.construct(p)
|
artifactsOnce[t][p].Do(func() {
|
||||||
return artifacts[t][p].a
|
artifacts[t][p], versions[t][p] = artifactsM[p].f(t)
|
||||||
|
})
|
||||||
|
return artifacts[t][p]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the version string of [PArtifact].
|
// Version returns the version string of [PArtifact].
|
||||||
func (t Toolchain) Version(p PArtifact) string {
|
func (t Toolchain) Version(p PArtifact) string {
|
||||||
t.construct(p)
|
artifactsOnce[t][p].Do(func() {
|
||||||
return artifacts[t][p].v
|
artifacts[t][p], versions[t][p] = artifactsM[p].f(t)
|
||||||
|
})
|
||||||
|
return versions[t][p]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveName returns a [PArtifact] by name.
|
// ResolveName returns a [PArtifact] by name.
|
||||||
|
|||||||
@@ -4,48 +4,24 @@ import "hakurei.app/internal/pkg"
|
|||||||
|
|
||||||
func (t Toolchain) newCurl() (pkg.Artifact, string) {
|
func (t Toolchain) newCurl() (pkg.Artifact, string) {
|
||||||
const (
|
const (
|
||||||
version = "8.19.0"
|
version = "8.18.0"
|
||||||
checksum = "YHuVLVVp8q_Y7-JWpID5ReNjq2Zk6t7ArHB6ngQXilp_R5l3cubdxu3UKo-xDByv"
|
checksum = "YpOolP_sx1DIrCEJ3elgVAu0wTLDS-EZMZFvOP0eha7FaLueZUlEpuMwDzJNyi7i"
|
||||||
)
|
)
|
||||||
return t.NewPackage("curl", version, pkg.NewHTTPGetTar(
|
return t.NewPackage("curl", version, pkg.NewHTTPGetTar(
|
||||||
nil, "https://curl.se/download/curl-"+version+".tar.bz2",
|
nil, "https://curl.se/download/curl-"+version+".tar.bz2",
|
||||||
mustDecode(checksum),
|
mustDecode(checksum),
|
||||||
pkg.TarBzip2,
|
pkg.TarBzip2,
|
||||||
), &PackageAttr{
|
), nil, &MakeHelper{
|
||||||
Patches: [][2]string{
|
|
||||||
{"test459-misplaced-line-break", `diff --git a/tests/data/test459 b/tests/data/test459
|
|
||||||
index 7a2e1db7b3..cc716aa65a 100644
|
|
||||||
--- a/tests/data/test459
|
|
||||||
+++ b/tests/data/test459
|
|
||||||
@@ -54,8 +54,8 @@ Content-Type: application/x-www-form-urlencoded
|
|
||||||
arg
|
|
||||||
</protocol>
|
|
||||||
<stderr mode="text">
|
|
||||||
-Warning: %LOGDIR/config:1 Option 'data' uses argument with unquoted whitespace.%SP
|
|
||||||
-Warning: This may cause side-effects. Consider double quotes.
|
|
||||||
+Warning: %LOGDIR/config:1 Option 'data' uses argument with unquoted%SP
|
|
||||||
+Warning: whitespace. This may cause side-effects. Consider double quotes.
|
|
||||||
</stderr>
|
|
||||||
</verify>
|
|
||||||
</testcase>
|
|
||||||
`},
|
|
||||||
},
|
|
||||||
}, &MakeHelper{
|
|
||||||
Configure: [][2]string{
|
Configure: [][2]string{
|
||||||
{"with-openssl"},
|
{"with-openssl"},
|
||||||
{"with-ca-bundle", "/system/etc/ssl/certs/ca-bundle.crt"},
|
{"with-ca-bundle", "/system/etc/ssl/certs/ca-bundle.crt"},
|
||||||
|
|
||||||
{"disable-smb"},
|
|
||||||
},
|
},
|
||||||
Check: []string{
|
Check: []string{
|
||||||
`TFLAGS="-j$(expr "$(nproc)" '*' 2)"`,
|
"TFLAGS=-j256",
|
||||||
"test-nonflaky",
|
"check",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Perl,
|
Perl,
|
||||||
Python,
|
|
||||||
PkgConfig,
|
|
||||||
Diffutils,
|
|
||||||
|
|
||||||
Libpsl,
|
Libpsl,
|
||||||
OpenSSL,
|
OpenSSL,
|
||||||
@@ -59,11 +35,6 @@ func init() {
|
|||||||
Description: "command line tool and library for transferring data with URLs",
|
Description: "command line tool and library for transferring data with URLs",
|
||||||
Website: "https://curl.se/",
|
Website: "https://curl.se/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Libpsl,
|
|
||||||
OpenSSL,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 381,
|
ID: 381,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,14 +46,6 @@ func init() {
|
|||||||
Description: "utilities and libraries to handle ELF files and DWARF data",
|
Description: "utilities and libraries to handle ELF files and DWARF data",
|
||||||
Website: "https://sourceware.org/elfutils/",
|
Website: "https://sourceware.org/elfutils/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zlib,
|
|
||||||
Bzip2,
|
|
||||||
Zstd,
|
|
||||||
MuslFts,
|
|
||||||
MuslObstack,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 5679,
|
ID: 5679,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ index f135ad9..85c784c 100644
|
|||||||
// makes assumptions about /etc/passwd
|
// makes assumptions about /etc/passwd
|
||||||
SkipCheck: true,
|
SkipCheck: true,
|
||||||
},
|
},
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
|
Autoconf,
|
||||||
Automake,
|
Automake,
|
||||||
Libtool,
|
Libtool,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ func (t Toolchain) newFuse() (pkg.Artifact, string) {
|
|||||||
// this project uses pytest
|
// this project uses pytest
|
||||||
SkipTest: true,
|
SkipTest: true,
|
||||||
},
|
},
|
||||||
|
PythonIniConfig,
|
||||||
|
PythonPackaging,
|
||||||
|
PythonPluggy,
|
||||||
|
PythonPygments,
|
||||||
PythonPyTest,
|
PythonPyTest,
|
||||||
|
|
||||||
KernelHeaders,
|
KernelHeaders,
|
||||||
|
|||||||
@@ -52,18 +52,16 @@ disable_test t2200-add-update
|
|||||||
`GIT_PROVE_OPTS="--jobs 32 --failures"`,
|
`GIT_PROVE_OPTS="--jobs 32 --failures"`,
|
||||||
"prove",
|
"prove",
|
||||||
},
|
},
|
||||||
Install: `make \
|
|
||||||
"-j$(nproc)" \
|
|
||||||
DESTDIR=/work \
|
|
||||||
NO_INSTALL_HARDLINKS=1 \
|
|
||||||
install`,
|
|
||||||
},
|
},
|
||||||
|
Perl,
|
||||||
Diffutils,
|
Diffutils,
|
||||||
|
M4,
|
||||||
Autoconf,
|
Autoconf,
|
||||||
Gettext,
|
Gettext,
|
||||||
|
|
||||||
Zlib,
|
Zlib,
|
||||||
Curl,
|
Curl,
|
||||||
|
OpenSSL,
|
||||||
Libexpat,
|
Libexpat,
|
||||||
), version
|
), version
|
||||||
}
|
}
|
||||||
@@ -75,12 +73,6 @@ func init() {
|
|||||||
Description: "distributed version control system",
|
Description: "distributed version control system",
|
||||||
Website: "https://www.git-scm.com/",
|
Website: "https://www.git-scm.com/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zlib,
|
|
||||||
Curl,
|
|
||||||
Libexpat,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 5350,
|
ID: 5350,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,10 +82,14 @@ func (t Toolchain) NewViaGit(
|
|||||||
name, url, rev string,
|
name, url, rev string,
|
||||||
checksum pkg.Checksum,
|
checksum pkg.Checksum,
|
||||||
) pkg.Artifact {
|
) pkg.Artifact {
|
||||||
return t.New(name+"-"+rev, 0, t.AppendPresets(nil,
|
return t.New(name+"-"+rev, 0, []pkg.Artifact{
|
||||||
NSSCACert,
|
t.Load(NSSCACert),
|
||||||
Git,
|
t.Load(OpenSSL),
|
||||||
), &checksum, nil, `
|
t.Load(Libpsl),
|
||||||
|
t.Load(Curl),
|
||||||
|
t.Load(Libexpat),
|
||||||
|
t.Load(Git),
|
||||||
|
}, &checksum, nil, `
|
||||||
git \
|
git \
|
||||||
-c advice.detachedHead=false \
|
-c advice.detachedHead=false \
|
||||||
clone \
|
clone \
|
||||||
|
|||||||
@@ -117,11 +117,6 @@ func init() {
|
|||||||
Description: "M4 macros to produce self-contained configure script",
|
Description: "M4 macros to produce self-contained configure script",
|
||||||
Website: "https://www.gnu.org/software/autoconf/",
|
Website: "https://www.gnu.org/software/autoconf/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
M4,
|
|
||||||
Perl,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 141,
|
ID: 141,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +143,8 @@ test_disable '#!/bin/sh' t/distname.sh
|
|||||||
test_disable '#!/bin/sh' t/pr9.sh
|
test_disable '#!/bin/sh' t/pr9.sh
|
||||||
`,
|
`,
|
||||||
}, (*MakeHelper)(nil),
|
}, (*MakeHelper)(nil),
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
Grep,
|
Grep,
|
||||||
Gzip,
|
Gzip,
|
||||||
Autoconf,
|
Autoconf,
|
||||||
@@ -162,10 +159,6 @@ func init() {
|
|||||||
Description: "a tool for automatically generating Makefile.in files",
|
Description: "a tool for automatically generating Makefile.in files",
|
||||||
Website: "https://www.gnu.org/software/automake/",
|
Website: "https://www.gnu.org/software/automake/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Autoconf,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 144,
|
ID: 144,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,11 +524,6 @@ func init() {
|
|||||||
Description: "the GNU square-wheel-reinvension of man pages",
|
Description: "the GNU square-wheel-reinvension of man pages",
|
||||||
Website: "https://www.gnu.org/software/texinfo/",
|
Website: "https://www.gnu.org/software/texinfo/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Perl,
|
|
||||||
Gawk,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 4958,
|
ID: 4958,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -672,6 +660,7 @@ func (t Toolchain) newBC() (pkg.Artifact, string) {
|
|||||||
Writable: true,
|
Writable: true,
|
||||||
Chmod: true,
|
Chmod: true,
|
||||||
}, (*MakeHelper)(nil),
|
}, (*MakeHelper)(nil),
|
||||||
|
Perl,
|
||||||
Texinfo,
|
Texinfo,
|
||||||
), version
|
), version
|
||||||
}
|
}
|
||||||
@@ -773,10 +762,6 @@ func init() {
|
|||||||
Description: "a shell tool for executing jobs in parallel using one or more computers",
|
Description: "a shell tool for executing jobs in parallel using one or more computers",
|
||||||
Website: "https://www.gnu.org/software/parallel/",
|
Website: "https://www.gnu.org/software/parallel/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Perl,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 5448,
|
ID: 5448,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -854,10 +839,6 @@ func init() {
|
|||||||
Description: "a C library for multiple-precision floating-point computations",
|
Description: "a C library for multiple-precision floating-point computations",
|
||||||
Website: "https://www.mpfr.org/",
|
Website: "https://www.mpfr.org/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
GMP,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 2019,
|
ID: 2019,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -873,6 +854,7 @@ func (t Toolchain) newMPC() (pkg.Artifact, string) {
|
|||||||
mustDecode(checksum),
|
mustDecode(checksum),
|
||||||
pkg.TarGzip,
|
pkg.TarGzip,
|
||||||
), nil, (*MakeHelper)(nil),
|
), nil, (*MakeHelper)(nil),
|
||||||
|
GMP,
|
||||||
MPFR,
|
MPFR,
|
||||||
), version
|
), version
|
||||||
}
|
}
|
||||||
@@ -884,10 +866,6 @@ func init() {
|
|||||||
Description: "a C library for the arithmetic of complex numbers",
|
Description: "a C library for the arithmetic of complex numbers",
|
||||||
Website: "https://www.multiprecision.org/",
|
Website: "https://www.multiprecision.org/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
MPFR,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 1667,
|
ID: 1667,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1063,10 @@ ln -s system/lib /work/
|
|||||||
},
|
},
|
||||||
Binutils,
|
Binutils,
|
||||||
|
|
||||||
|
GMP,
|
||||||
|
MPFR,
|
||||||
MPC,
|
MPC,
|
||||||
|
|
||||||
Zlib,
|
Zlib,
|
||||||
Libucontext,
|
Libucontext,
|
||||||
KernelHeaders,
|
KernelHeaders,
|
||||||
@@ -1099,14 +1080,6 @@ func init() {
|
|||||||
Description: "The GNU Compiler Collection",
|
Description: "The GNU Compiler Collection",
|
||||||
Website: "https://www.gnu.org/software/gcc/",
|
Website: "https://www.gnu.org/software/gcc/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Binutils,
|
|
||||||
|
|
||||||
MPC,
|
|
||||||
Zlib,
|
|
||||||
Libucontext,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 6502,
|
ID: 6502,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,8 +74,22 @@ func (t Toolchain) newGoLatest() (pkg.Artifact, string) {
|
|||||||
bootstrapExtra = append(bootstrapExtra, t.newGoBootstrap())
|
bootstrapExtra = append(bootstrapExtra, t.newGoBootstrap())
|
||||||
|
|
||||||
case "arm64":
|
case "arm64":
|
||||||
bootstrapEnv = append(bootstrapEnv, "GOROOT_BOOTSTRAP=/system")
|
bootstrapEnv = append(bootstrapEnv,
|
||||||
bootstrapExtra = t.AppendPresets(bootstrapExtra, gcc)
|
"GOROOT_BOOTSTRAP=/system",
|
||||||
|
)
|
||||||
|
bootstrapExtra = append(bootstrapExtra,
|
||||||
|
t.Load(Binutils),
|
||||||
|
|
||||||
|
t.Load(GMP),
|
||||||
|
t.Load(MPFR),
|
||||||
|
t.Load(MPC),
|
||||||
|
|
||||||
|
t.Load(Zlib),
|
||||||
|
t.Load(Libucontext),
|
||||||
|
|
||||||
|
t.Load(gcc),
|
||||||
|
)
|
||||||
|
|
||||||
finalEnv = append(finalEnv, "CGO_ENABLED=0")
|
finalEnv = append(finalEnv, "CGO_ENABLED=0")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
func (t Toolchain) newGLib() (pkg.Artifact, string) {
|
func (t Toolchain) newGLib() (pkg.Artifact, string) {
|
||||||
const (
|
const (
|
||||||
version = "2.87.5"
|
version = "2.87.3"
|
||||||
checksum = "L5jurSfyCTlcSTfx-1RBHbNZPL0HnNQakmFXidgAV1JFu0lbytowCCBAALTp-WGc"
|
checksum = "iKSLpzZZVfmAZZmqfO1y6uHdlIks4hzPWrqeUCp4ZeQjrPFA3aAa4OmrBYMNS-Si"
|
||||||
)
|
)
|
||||||
return t.NewPackage("glib", version, pkg.NewHTTPGet(
|
return t.NewPackage("glib", version, pkg.NewHTTPGet(
|
||||||
nil, "https://download.gnome.org/sources/glib/"+
|
nil, "https://download.gnome.org/sources/glib/"+
|
||||||
@@ -56,12 +56,6 @@ func init() {
|
|||||||
Description: "the GNU library of miscellaneous stuff",
|
Description: "the GNU library of miscellaneous stuff",
|
||||||
Website: "https://developer.gnome.org/glib/",
|
Website: "https://developer.gnome.org/glib/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
PCRE2,
|
|
||||||
Libffi,
|
|
||||||
Zlib,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 10024,
|
ID: 10024,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,23 +15,29 @@ echo
|
|||||||
hostname = ""
|
hostname = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.New("hakurei"+suffix+"-"+hakureiVersion, 0, t.AppendPresets(nil,
|
return t.New("hakurei"+suffix+"-"+hakureiVersion, 0, []pkg.Artifact{
|
||||||
Go,
|
t.Load(Go),
|
||||||
PkgConfig,
|
|
||||||
|
|
||||||
// dist tarball
|
t.Load(Gzip),
|
||||||
Gzip,
|
t.Load(PkgConfig),
|
||||||
|
|
||||||
// statically linked
|
t.Load(KernelHeaders),
|
||||||
Libseccomp,
|
t.Load(Libseccomp),
|
||||||
ACL,
|
t.Load(ACL),
|
||||||
Fuse,
|
t.Load(Attr),
|
||||||
XCB,
|
t.Load(Fuse),
|
||||||
Wayland,
|
|
||||||
WaylandProtocols,
|
|
||||||
|
|
||||||
KernelHeaders,
|
t.Load(Xproto),
|
||||||
), nil, []string{
|
t.Load(LibXau),
|
||||||
|
t.Load(XCBProto),
|
||||||
|
t.Load(XCB),
|
||||||
|
|
||||||
|
t.Load(Libffi),
|
||||||
|
t.Load(Libexpat),
|
||||||
|
t.Load(Libxml2),
|
||||||
|
t.Load(Wayland),
|
||||||
|
t.Load(WaylandProtocols),
|
||||||
|
}, nil, []string{
|
||||||
"CGO_ENABLED=1",
|
"CGO_ENABLED=1",
|
||||||
"GOCACHE=/tmp/gocache",
|
"GOCACHE=/tmp/gocache",
|
||||||
"CC=clang -O3 -Werror",
|
"CC=clang -O3 -Werror",
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package rosa
|
package rosa
|
||||||
|
|
||||||
import (
|
import "hakurei.app/internal/pkg"
|
||||||
"hakurei.app/container/fhs"
|
|
||||||
"hakurei.app/internal/pkg"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
artifactsM[EarlyInit] = Metadata{
|
artifactsM[EarlyInit] = Metadata{
|
||||||
@@ -27,36 +24,12 @@ echo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Toolchain) newImageSystem() (pkg.Artifact, string) {
|
|
||||||
return t.New("system.img", TNoToolchain, t.AppendPresets(nil,
|
|
||||||
SquashfsTools,
|
|
||||||
), nil, nil, `
|
|
||||||
mksquashfs /mnt/system /work/system.img
|
|
||||||
`, pkg.Path(fhs.AbsRoot.Append("mnt"), false, t.AppendPresets(nil,
|
|
||||||
Musl,
|
|
||||||
Mksh,
|
|
||||||
Toybox,
|
|
||||||
|
|
||||||
Kmod,
|
|
||||||
Kernel,
|
|
||||||
Firmware,
|
|
||||||
)...)), Unversioned
|
|
||||||
}
|
|
||||||
func init() {
|
|
||||||
artifactsM[ImageSystem] = Metadata{
|
|
||||||
Name: "system-image",
|
|
||||||
Description: "Rosa OS system image",
|
|
||||||
|
|
||||||
f: Toolchain.newImageSystem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Toolchain) newImageInitramfs() (pkg.Artifact, string) {
|
func (t Toolchain) newImageInitramfs() (pkg.Artifact, string) {
|
||||||
return t.New("initramfs", TNoToolchain, t.AppendPresets(nil,
|
return t.New("initramfs", TNoToolchain, []pkg.Artifact{
|
||||||
Zstd,
|
t.Load(Zstd),
|
||||||
EarlyInit,
|
t.Load(EarlyInit),
|
||||||
GenInitCPIO,
|
t.Load(GenInitCPIO),
|
||||||
), nil, nil, `
|
}, nil, nil, `
|
||||||
gen_init_cpio -t 4294967295 -c /usr/src/initramfs | zstd > /work/initramfs.zst
|
gen_init_cpio -t 4294967295 -c /usr/src/initramfs | zstd > /work/initramfs.zst
|
||||||
`, pkg.Path(AbsUsrSrc.Append("initramfs"), false, pkg.NewFile("initramfs", []byte(`
|
`, pkg.Path(AbsUsrSrc.Append("initramfs"), false, pkg.NewFile("initramfs", []byte(`
|
||||||
dir /dev 0755 0 0
|
dir /dev 0755 0 0
|
||||||
|
|||||||
@@ -82,11 +82,6 @@ install -Dm0500 \
|
|||||||
echo "Installing linux $1..."
|
echo "Installing linux $1..."
|
||||||
cp -av "$2" "$4"
|
cp -av "$2" "$4"
|
||||||
cp -av "$3" "$4"
|
cp -av "$3" "$4"
|
||||||
`))),
|
|
||||||
pkg.Path(AbsUsrSrc.Append(
|
|
||||||
".depmod",
|
|
||||||
), false, pkg.NewFile("depmod", []byte(`#!/bin/sh
|
|
||||||
exec /system/sbin/depmod -m /lib/modules "$@"
|
|
||||||
`))),
|
`))),
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1215,11 +1210,6 @@ cgit 1.2.3-korg
|
|||||||
"all",
|
"all",
|
||||||
},
|
},
|
||||||
Install: `
|
Install: `
|
||||||
# kernel is not aware of kmod moduledir
|
|
||||||
install -Dm0500 \
|
|
||||||
/usr/src/.depmod \
|
|
||||||
/sbin/depmod
|
|
||||||
|
|
||||||
make \
|
make \
|
||||||
"-j$(nproc)" \
|
"-j$(nproc)" \
|
||||||
-f /usr/src/kernel/Makefile \
|
-f /usr/src/kernel/Makefile \
|
||||||
@@ -1227,10 +1217,9 @@ make \
|
|||||||
LLVM=1 \
|
LLVM=1 \
|
||||||
INSTALL_PATH=/work \
|
INSTALL_PATH=/work \
|
||||||
install \
|
install \
|
||||||
INSTALL_MOD_PATH=/work/system \
|
INSTALL_MOD_PATH=/work \
|
||||||
DEPMOD=/sbin/depmod \
|
|
||||||
modules_install
|
modules_install
|
||||||
rm -v /work/system/lib/modules/` + kernelVersion + `/build
|
rm -v /work/lib/modules/` + kernelVersion + `/build
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
Flex,
|
Flex,
|
||||||
@@ -1246,9 +1235,13 @@ rm -v /work/system/lib/modules/` + kernelVersion + `/build
|
|||||||
Python,
|
Python,
|
||||||
|
|
||||||
XZ,
|
XZ,
|
||||||
|
Zlib,
|
||||||
Gzip,
|
Gzip,
|
||||||
|
Bzip2,
|
||||||
|
Zstd,
|
||||||
Kmod,
|
Kmod,
|
||||||
Elfutils,
|
Elfutils,
|
||||||
|
OpenSSL,
|
||||||
UtilLinux,
|
UtilLinux,
|
||||||
KernelHeaders,
|
KernelHeaders,
|
||||||
), kernelVersion
|
), kernelVersion
|
||||||
@@ -1282,8 +1275,8 @@ func init() {
|
|||||||
|
|
||||||
func (t Toolchain) newFirmware() (pkg.Artifact, string) {
|
func (t Toolchain) newFirmware() (pkg.Artifact, string) {
|
||||||
const (
|
const (
|
||||||
version = "20260309"
|
version = "20260221"
|
||||||
checksum = "M1az8BxSiOEH3LA11Trc5VAlakwAHhP7-_LKWg6k-SVIzU3xclMDO4Tiujw1gQrC"
|
checksum = "vTENPW5rZ6yLVq7YKDLHkCVgKXvwUWigEx7T4LcxoKeBVYIyf1_sEExeV4mo-e46"
|
||||||
)
|
)
|
||||||
return t.NewPackage("firmware", version, pkg.NewHTTPGetTar(
|
return t.NewPackage("firmware", version, pkg.NewHTTPGetTar(
|
||||||
nil, "https://gitlab.com/kernel-firmware/linux-firmware/-/"+
|
nil, "https://gitlab.com/kernel-firmware/linux-firmware/-/"+
|
||||||
@@ -1311,7 +1304,9 @@ func (t Toolchain) newFirmware() (pkg.Artifact, string) {
|
|||||||
SkipCheck: true, // requires pre-commit
|
SkipCheck: true, // requires pre-commit
|
||||||
Install: `make "-j$(nproc)" DESTDIR=/work/system dedup`,
|
Install: `make "-j$(nproc)" DESTDIR=/work/system dedup`,
|
||||||
},
|
},
|
||||||
|
Perl,
|
||||||
Parallel,
|
Parallel,
|
||||||
|
Nettle,
|
||||||
Rdfind,
|
Rdfind,
|
||||||
Zstd,
|
Zstd,
|
||||||
Findutils,
|
Findutils,
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/x86 6.12.76 Kernel Configuration
|
# Linux/x86 6.12.76 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="clang version 22.1.1"
|
CONFIG_CC_VERSION_TEXT="clang version 22.1.0"
|
||||||
CONFIG_GCC_VERSION=0
|
CONFIG_GCC_VERSION=0
|
||||||
CONFIG_CC_IS_CLANG=y
|
CONFIG_CC_IS_CLANG=y
|
||||||
CONFIG_CLANG_VERSION=220101
|
CONFIG_CLANG_VERSION=220100
|
||||||
CONFIG_AS_IS_LLVM=y
|
CONFIG_AS_IS_LLVM=y
|
||||||
CONFIG_AS_VERSION=220101
|
CONFIG_AS_VERSION=220100
|
||||||
CONFIG_LD_VERSION=0
|
CONFIG_LD_VERSION=0
|
||||||
CONFIG_LD_IS_LLD=y
|
CONFIG_LD_IS_LLD=y
|
||||||
CONFIG_LLD_VERSION=220101
|
CONFIG_LLD_VERSION=220100
|
||||||
CONFIG_RUSTC_VERSION=0
|
CONFIG_RUSTC_VERSION=0
|
||||||
CONFIG_RUSTC_LLVM_VERSION=0
|
CONFIG_RUSTC_LLVM_VERSION=0
|
||||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||||
@@ -2402,7 +2402,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
|
|||||||
#
|
#
|
||||||
# Firmware loader
|
# Firmware loader
|
||||||
#
|
#
|
||||||
CONFIG_FW_LOADER=y
|
CONFIG_FW_LOADER=m
|
||||||
CONFIG_FW_LOADER_DEBUG=y
|
CONFIG_FW_LOADER_DEBUG=y
|
||||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||||
CONFIG_FW_LOADER_SYSFS=y
|
CONFIG_FW_LOADER_SYSFS=y
|
||||||
@@ -2749,7 +2749,7 @@ CONFIG_BLK_DEV_NULL_BLK=m
|
|||||||
CONFIG_BLK_DEV_FD=m
|
CONFIG_BLK_DEV_FD=m
|
||||||
# CONFIG_BLK_DEV_FD_RAWCMD is not set
|
# CONFIG_BLK_DEV_FD_RAWCMD is not set
|
||||||
CONFIG_CDROM=m
|
CONFIG_CDROM=m
|
||||||
CONFIG_BLK_DEV_PCIESSD_MTIP32XX=y
|
CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
|
||||||
CONFIG_ZRAM=m
|
CONFIG_ZRAM=m
|
||||||
# CONFIG_ZRAM_BACKEND_LZ4 is not set
|
# CONFIG_ZRAM_BACKEND_LZ4 is not set
|
||||||
# CONFIG_ZRAM_BACKEND_LZ4HC is not set
|
# CONFIG_ZRAM_BACKEND_LZ4HC is not set
|
||||||
@@ -2775,9 +2775,9 @@ CONFIG_CDROM_PKTCDVD=m
|
|||||||
CONFIG_CDROM_PKTCDVD_BUFFERS=8
|
CONFIG_CDROM_PKTCDVD_BUFFERS=8
|
||||||
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
|
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
|
||||||
CONFIG_ATA_OVER_ETH=m
|
CONFIG_ATA_OVER_ETH=m
|
||||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
CONFIG_XEN_BLKDEV_FRONTEND=m
|
||||||
# CONFIG_XEN_BLKDEV_BACKEND is not set
|
CONFIG_XEN_BLKDEV_BACKEND=m
|
||||||
CONFIG_VIRTIO_BLK=y
|
CONFIG_VIRTIO_BLK=m
|
||||||
CONFIG_BLK_DEV_RBD=m
|
CONFIG_BLK_DEV_RBD=m
|
||||||
CONFIG_BLK_DEV_UBLK=m
|
CONFIG_BLK_DEV_UBLK=m
|
||||||
CONFIG_BLKDEV_UBLK_LEGACY_OPCODES=y
|
CONFIG_BLKDEV_UBLK_LEGACY_OPCODES=y
|
||||||
@@ -2788,12 +2788,13 @@ CONFIG_BLK_DEV_RNBD_SERVER=m
|
|||||||
#
|
#
|
||||||
# NVME Support
|
# NVME Support
|
||||||
#
|
#
|
||||||
CONFIG_NVME_KEYRING=y
|
CONFIG_NVME_KEYRING=m
|
||||||
CONFIG_NVME_AUTH=y
|
CONFIG_NVME_AUTH=m
|
||||||
CONFIG_NVME_CORE=y
|
CONFIG_NVME_CORE=m
|
||||||
CONFIG_BLK_DEV_NVME=y
|
CONFIG_BLK_DEV_NVME=m
|
||||||
CONFIG_NVME_MULTIPATH=y
|
CONFIG_NVME_MULTIPATH=y
|
||||||
# CONFIG_NVME_VERBOSE_ERRORS is not set
|
# CONFIG_NVME_VERBOSE_ERRORS is not set
|
||||||
|
CONFIG_NVME_HWMON=y
|
||||||
CONFIG_NVME_FABRICS=m
|
CONFIG_NVME_FABRICS=m
|
||||||
CONFIG_NVME_RDMA=m
|
CONFIG_NVME_RDMA=m
|
||||||
CONFIG_NVME_FC=m
|
CONFIG_NVME_FC=m
|
||||||
@@ -2910,10 +2911,10 @@ CONFIG_KEBA_CP500=m
|
|||||||
#
|
#
|
||||||
# SCSI device support
|
# SCSI device support
|
||||||
#
|
#
|
||||||
CONFIG_SCSI_MOD=y
|
CONFIG_SCSI_MOD=m
|
||||||
CONFIG_RAID_ATTRS=m
|
CONFIG_RAID_ATTRS=m
|
||||||
CONFIG_SCSI_COMMON=y
|
CONFIG_SCSI_COMMON=m
|
||||||
CONFIG_SCSI=y
|
CONFIG_SCSI=m
|
||||||
CONFIG_SCSI_DMA=y
|
CONFIG_SCSI_DMA=y
|
||||||
CONFIG_SCSI_NETLINK=y
|
CONFIG_SCSI_NETLINK=y
|
||||||
CONFIG_SCSI_PROC_FS=y
|
CONFIG_SCSI_PROC_FS=y
|
||||||
@@ -2921,7 +2922,7 @@ CONFIG_SCSI_PROC_FS=y
|
|||||||
#
|
#
|
||||||
# SCSI support type (disk, tape, CD-ROM)
|
# SCSI support type (disk, tape, CD-ROM)
|
||||||
#
|
#
|
||||||
CONFIG_BLK_DEV_SD=y
|
CONFIG_BLK_DEV_SD=m
|
||||||
CONFIG_CHR_DEV_ST=m
|
CONFIG_CHR_DEV_ST=m
|
||||||
CONFIG_BLK_DEV_SR=m
|
CONFIG_BLK_DEV_SR=m
|
||||||
CONFIG_CHR_DEV_SG=m
|
CONFIG_CHR_DEV_SG=m
|
||||||
@@ -3041,7 +3042,7 @@ CONFIG_SCSI_DEBUG=m
|
|||||||
CONFIG_SCSI_PMCRAID=m
|
CONFIG_SCSI_PMCRAID=m
|
||||||
CONFIG_SCSI_PM8001=m
|
CONFIG_SCSI_PM8001=m
|
||||||
CONFIG_SCSI_BFA_FC=m
|
CONFIG_SCSI_BFA_FC=m
|
||||||
CONFIG_SCSI_VIRTIO=y
|
CONFIG_SCSI_VIRTIO=m
|
||||||
CONFIG_SCSI_CHELSIO_FCOE=m
|
CONFIG_SCSI_CHELSIO_FCOE=m
|
||||||
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
|
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
|
||||||
CONFIG_PCMCIA_AHA152X=m
|
CONFIG_PCMCIA_AHA152X=m
|
||||||
@@ -3051,7 +3052,7 @@ CONFIG_PCMCIA_SYM53C500=m
|
|||||||
# CONFIG_SCSI_DH is not set
|
# CONFIG_SCSI_DH is not set
|
||||||
# end of SCSI device support
|
# end of SCSI device support
|
||||||
|
|
||||||
CONFIG_ATA=y
|
CONFIG_ATA=m
|
||||||
CONFIG_SATA_HOST=y
|
CONFIG_SATA_HOST=y
|
||||||
CONFIG_PATA_TIMINGS=y
|
CONFIG_PATA_TIMINGS=y
|
||||||
CONFIG_ATA_VERBOSE_ERROR=y
|
CONFIG_ATA_VERBOSE_ERROR=y
|
||||||
@@ -3063,39 +3064,39 @@ CONFIG_SATA_PMP=y
|
|||||||
#
|
#
|
||||||
# Controllers with non-SFF native interface
|
# Controllers with non-SFF native interface
|
||||||
#
|
#
|
||||||
CONFIG_SATA_AHCI=y
|
CONFIG_SATA_AHCI=m
|
||||||
CONFIG_SATA_MOBILE_LPM_POLICY=3
|
CONFIG_SATA_MOBILE_LPM_POLICY=3
|
||||||
CONFIG_SATA_AHCI_PLATFORM=y
|
CONFIG_SATA_AHCI_PLATFORM=m
|
||||||
CONFIG_AHCI_DWC=y
|
CONFIG_AHCI_DWC=m
|
||||||
CONFIG_AHCI_CEVA=y
|
CONFIG_AHCI_CEVA=m
|
||||||
CONFIG_SATA_INIC162X=m
|
CONFIG_SATA_INIC162X=m
|
||||||
CONFIG_SATA_ACARD_AHCI=y
|
CONFIG_SATA_ACARD_AHCI=m
|
||||||
CONFIG_SATA_SIL24=y
|
CONFIG_SATA_SIL24=m
|
||||||
CONFIG_ATA_SFF=y
|
CONFIG_ATA_SFF=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# SFF controllers with custom DMA interface
|
# SFF controllers with custom DMA interface
|
||||||
#
|
#
|
||||||
CONFIG_PDC_ADMA=y
|
CONFIG_PDC_ADMA=m
|
||||||
CONFIG_SATA_QSTOR=y
|
CONFIG_SATA_QSTOR=m
|
||||||
CONFIG_SATA_SX4=m
|
CONFIG_SATA_SX4=m
|
||||||
CONFIG_ATA_BMDMA=y
|
CONFIG_ATA_BMDMA=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# SATA SFF controllers with BMDMA
|
# SATA SFF controllers with BMDMA
|
||||||
#
|
#
|
||||||
CONFIG_ATA_PIIX=y
|
CONFIG_ATA_PIIX=m
|
||||||
CONFIG_SATA_DWC=y
|
CONFIG_SATA_DWC=m
|
||||||
# CONFIG_SATA_DWC_OLD_DMA is not set
|
# CONFIG_SATA_DWC_OLD_DMA is not set
|
||||||
CONFIG_SATA_MV=y
|
CONFIG_SATA_MV=m
|
||||||
CONFIG_SATA_NV=y
|
CONFIG_SATA_NV=m
|
||||||
CONFIG_SATA_PROMISE=y
|
CONFIG_SATA_PROMISE=m
|
||||||
CONFIG_SATA_SIL=y
|
CONFIG_SATA_SIL=m
|
||||||
CONFIG_SATA_SIS=y
|
CONFIG_SATA_SIS=m
|
||||||
CONFIG_SATA_SVW=y
|
CONFIG_SATA_SVW=m
|
||||||
CONFIG_SATA_ULI=y
|
CONFIG_SATA_ULI=m
|
||||||
CONFIG_SATA_VIA=y
|
CONFIG_SATA_VIA=m
|
||||||
CONFIG_SATA_VITESSE=y
|
CONFIG_SATA_VITESSE=m
|
||||||
|
|
||||||
#
|
#
|
||||||
# PATA SFF controllers with BMDMA
|
# PATA SFF controllers with BMDMA
|
||||||
@@ -3129,7 +3130,7 @@ CONFIG_PATA_RDC=m
|
|||||||
CONFIG_PATA_SCH=m
|
CONFIG_PATA_SCH=m
|
||||||
CONFIG_PATA_SERVERWORKS=m
|
CONFIG_PATA_SERVERWORKS=m
|
||||||
CONFIG_PATA_SIL680=m
|
CONFIG_PATA_SIL680=m
|
||||||
CONFIG_PATA_SIS=y
|
CONFIG_PATA_SIS=m
|
||||||
CONFIG_PATA_TOSHIBA=m
|
CONFIG_PATA_TOSHIBA=m
|
||||||
CONFIG_PATA_TRIFLEX=m
|
CONFIG_PATA_TRIFLEX=m
|
||||||
CONFIG_PATA_VIA=m
|
CONFIG_PATA_VIA=m
|
||||||
@@ -3171,8 +3172,8 @@ CONFIG_PATA_PARPORT_ON26=m
|
|||||||
#
|
#
|
||||||
# Generic fallback / legacy drivers
|
# Generic fallback / legacy drivers
|
||||||
#
|
#
|
||||||
CONFIG_PATA_ACPI=y
|
CONFIG_PATA_ACPI=m
|
||||||
CONFIG_ATA_GENERIC=y
|
CONFIG_ATA_GENERIC=m
|
||||||
CONFIG_PATA_LEGACY=m
|
CONFIG_PATA_LEGACY=m
|
||||||
CONFIG_MD=y
|
CONFIG_MD=y
|
||||||
CONFIG_BLK_DEV_MD=m
|
CONFIG_BLK_DEV_MD=m
|
||||||
@@ -9620,11 +9621,11 @@ CONFIG_EFI_SECRET=m
|
|||||||
CONFIG_SEV_GUEST=m
|
CONFIG_SEV_GUEST=m
|
||||||
CONFIG_TDX_GUEST_DRIVER=m
|
CONFIG_TDX_GUEST_DRIVER=m
|
||||||
CONFIG_VIRTIO_ANCHOR=y
|
CONFIG_VIRTIO_ANCHOR=y
|
||||||
CONFIG_VIRTIO=y
|
CONFIG_VIRTIO=m
|
||||||
CONFIG_VIRTIO_PCI_LIB=y
|
CONFIG_VIRTIO_PCI_LIB=m
|
||||||
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
|
CONFIG_VIRTIO_PCI_LIB_LEGACY=m
|
||||||
CONFIG_VIRTIO_MENU=y
|
CONFIG_VIRTIO_MENU=y
|
||||||
CONFIG_VIRTIO_PCI=y
|
CONFIG_VIRTIO_PCI=m
|
||||||
CONFIG_VIRTIO_PCI_ADMIN_LEGACY=y
|
CONFIG_VIRTIO_PCI_ADMIN_LEGACY=y
|
||||||
CONFIG_VIRTIO_PCI_LEGACY=y
|
CONFIG_VIRTIO_PCI_LEGACY=y
|
||||||
CONFIG_VIRTIO_VDPA=m
|
CONFIG_VIRTIO_VDPA=m
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/arm64 6.12.76 Kernel Configuration
|
# Linux/arm64 6.12.76 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="clang version 22.1.1"
|
CONFIG_CC_VERSION_TEXT="clang version 22.1.0"
|
||||||
CONFIG_GCC_VERSION=0
|
CONFIG_GCC_VERSION=0
|
||||||
CONFIG_CC_IS_CLANG=y
|
CONFIG_CC_IS_CLANG=y
|
||||||
CONFIG_CLANG_VERSION=220101
|
CONFIG_CLANG_VERSION=220100
|
||||||
CONFIG_AS_IS_LLVM=y
|
CONFIG_AS_IS_LLVM=y
|
||||||
CONFIG_AS_VERSION=220101
|
CONFIG_AS_VERSION=220100
|
||||||
CONFIG_LD_VERSION=0
|
CONFIG_LD_VERSION=0
|
||||||
CONFIG_LD_IS_LLD=y
|
CONFIG_LD_IS_LLD=y
|
||||||
CONFIG_LLD_VERSION=220101
|
CONFIG_LLD_VERSION=220100
|
||||||
CONFIG_RUSTC_VERSION=0
|
CONFIG_RUSTC_VERSION=0
|
||||||
CONFIG_RUSTC_LLVM_VERSION=0
|
CONFIG_RUSTC_LLVM_VERSION=0
|
||||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||||
@@ -2384,7 +2384,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
|
|||||||
#
|
#
|
||||||
# Firmware loader
|
# Firmware loader
|
||||||
#
|
#
|
||||||
CONFIG_FW_LOADER=y
|
CONFIG_FW_LOADER=m
|
||||||
CONFIG_FW_LOADER_DEBUG=y
|
CONFIG_FW_LOADER_DEBUG=y
|
||||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||||
CONFIG_FW_LOADER_SYSFS=y
|
CONFIG_FW_LOADER_SYSFS=y
|
||||||
@@ -2849,8 +2849,8 @@ CONFIG_CDROM_PKTCDVD=m
|
|||||||
CONFIG_CDROM_PKTCDVD_BUFFERS=8
|
CONFIG_CDROM_PKTCDVD_BUFFERS=8
|
||||||
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
|
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
|
||||||
CONFIG_ATA_OVER_ETH=m
|
CONFIG_ATA_OVER_ETH=m
|
||||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
CONFIG_XEN_BLKDEV_FRONTEND=m
|
||||||
# CONFIG_XEN_BLKDEV_BACKEND is not set
|
CONFIG_XEN_BLKDEV_BACKEND=m
|
||||||
CONFIG_VIRTIO_BLK=m
|
CONFIG_VIRTIO_BLK=m
|
||||||
CONFIG_BLK_DEV_RBD=m
|
CONFIG_BLK_DEV_RBD=m
|
||||||
CONFIG_BLK_DEV_UBLK=m
|
CONFIG_BLK_DEV_UBLK=m
|
||||||
@@ -2862,12 +2862,13 @@ CONFIG_BLK_DEV_RNBD_SERVER=m
|
|||||||
#
|
#
|
||||||
# NVME Support
|
# NVME Support
|
||||||
#
|
#
|
||||||
CONFIG_NVME_KEYRING=y
|
CONFIG_NVME_KEYRING=m
|
||||||
CONFIG_NVME_AUTH=y
|
CONFIG_NVME_AUTH=m
|
||||||
CONFIG_NVME_CORE=y
|
CONFIG_NVME_CORE=m
|
||||||
CONFIG_BLK_DEV_NVME=y
|
CONFIG_BLK_DEV_NVME=m
|
||||||
CONFIG_NVME_MULTIPATH=y
|
CONFIG_NVME_MULTIPATH=y
|
||||||
# CONFIG_NVME_VERBOSE_ERRORS is not set
|
# CONFIG_NVME_VERBOSE_ERRORS is not set
|
||||||
|
CONFIG_NVME_HWMON=y
|
||||||
CONFIG_NVME_FABRICS=m
|
CONFIG_NVME_FABRICS=m
|
||||||
CONFIG_NVME_RDMA=m
|
CONFIG_NVME_RDMA=m
|
||||||
CONFIG_NVME_FC=m
|
CONFIG_NVME_FC=m
|
||||||
@@ -2976,10 +2977,10 @@ CONFIG_KEBA_CP500=m
|
|||||||
#
|
#
|
||||||
# SCSI device support
|
# SCSI device support
|
||||||
#
|
#
|
||||||
CONFIG_SCSI_MOD=y
|
CONFIG_SCSI_MOD=m
|
||||||
CONFIG_RAID_ATTRS=m
|
CONFIG_RAID_ATTRS=m
|
||||||
CONFIG_SCSI_COMMON=y
|
CONFIG_SCSI_COMMON=m
|
||||||
CONFIG_SCSI=y
|
CONFIG_SCSI=m
|
||||||
CONFIG_SCSI_DMA=y
|
CONFIG_SCSI_DMA=y
|
||||||
CONFIG_SCSI_NETLINK=y
|
CONFIG_SCSI_NETLINK=y
|
||||||
CONFIG_SCSI_PROC_FS=y
|
CONFIG_SCSI_PROC_FS=y
|
||||||
@@ -2987,7 +2988,7 @@ CONFIG_SCSI_PROC_FS=y
|
|||||||
#
|
#
|
||||||
# SCSI support type (disk, tape, CD-ROM)
|
# SCSI support type (disk, tape, CD-ROM)
|
||||||
#
|
#
|
||||||
CONFIG_BLK_DEV_SD=y
|
CONFIG_BLK_DEV_SD=m
|
||||||
CONFIG_CHR_DEV_ST=m
|
CONFIG_CHR_DEV_ST=m
|
||||||
CONFIG_BLK_DEV_SR=m
|
CONFIG_BLK_DEV_SR=m
|
||||||
CONFIG_CHR_DEV_SG=m
|
CONFIG_CHR_DEV_SG=m
|
||||||
@@ -3107,7 +3108,7 @@ CONFIG_SCSI_DEBUG=m
|
|||||||
CONFIG_SCSI_PMCRAID=m
|
CONFIG_SCSI_PMCRAID=m
|
||||||
CONFIG_SCSI_PM8001=m
|
CONFIG_SCSI_PM8001=m
|
||||||
CONFIG_SCSI_BFA_FC=m
|
CONFIG_SCSI_BFA_FC=m
|
||||||
CONFIG_SCSI_VIRTIO=y
|
CONFIG_SCSI_VIRTIO=m
|
||||||
CONFIG_SCSI_CHELSIO_FCOE=m
|
CONFIG_SCSI_CHELSIO_FCOE=m
|
||||||
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
|
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
|
||||||
CONFIG_PCMCIA_AHA152X=m
|
CONFIG_PCMCIA_AHA152X=m
|
||||||
@@ -3117,7 +3118,7 @@ CONFIG_PCMCIA_SYM53C500=m
|
|||||||
# CONFIG_SCSI_DH is not set
|
# CONFIG_SCSI_DH is not set
|
||||||
# end of SCSI device support
|
# end of SCSI device support
|
||||||
|
|
||||||
CONFIG_ATA=y
|
CONFIG_ATA=m
|
||||||
CONFIG_SATA_HOST=y
|
CONFIG_SATA_HOST=y
|
||||||
CONFIG_PATA_TIMINGS=y
|
CONFIG_PATA_TIMINGS=y
|
||||||
CONFIG_ATA_VERBOSE_ERROR=y
|
CONFIG_ATA_VERBOSE_ERROR=y
|
||||||
@@ -3129,23 +3130,23 @@ CONFIG_SATA_PMP=y
|
|||||||
#
|
#
|
||||||
# Controllers with non-SFF native interface
|
# Controllers with non-SFF native interface
|
||||||
#
|
#
|
||||||
CONFIG_SATA_AHCI=y
|
CONFIG_SATA_AHCI=m
|
||||||
CONFIG_SATA_MOBILE_LPM_POLICY=3
|
CONFIG_SATA_MOBILE_LPM_POLICY=3
|
||||||
CONFIG_SATA_AHCI_PLATFORM=y
|
CONFIG_SATA_AHCI_PLATFORM=m
|
||||||
CONFIG_AHCI_BRCM=y
|
CONFIG_AHCI_BRCM=m
|
||||||
CONFIG_AHCI_DWC=y
|
CONFIG_AHCI_DWC=m
|
||||||
CONFIG_AHCI_IMX=m
|
CONFIG_AHCI_IMX=m
|
||||||
CONFIG_AHCI_CEVA=y
|
CONFIG_AHCI_CEVA=m
|
||||||
CONFIG_AHCI_MTK=y
|
CONFIG_AHCI_MTK=m
|
||||||
CONFIG_AHCI_MVEBU=y
|
CONFIG_AHCI_MVEBU=m
|
||||||
CONFIG_AHCI_SUNXI=y
|
CONFIG_AHCI_SUNXI=m
|
||||||
CONFIG_AHCI_TEGRA=y
|
CONFIG_AHCI_TEGRA=m
|
||||||
CONFIG_AHCI_XGENE=m
|
CONFIG_AHCI_XGENE=m
|
||||||
CONFIG_AHCI_QORIQ=y
|
CONFIG_AHCI_QORIQ=m
|
||||||
CONFIG_SATA_AHCI_SEATTLE=y
|
CONFIG_SATA_AHCI_SEATTLE=m
|
||||||
CONFIG_SATA_INIC162X=m
|
CONFIG_SATA_INIC162X=m
|
||||||
CONFIG_SATA_ACARD_AHCI=y
|
CONFIG_SATA_ACARD_AHCI=m
|
||||||
CONFIG_SATA_SIL24=y
|
CONFIG_SATA_SIL24=m
|
||||||
CONFIG_ATA_SFF=y
|
CONFIG_ATA_SFF=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -3159,19 +3160,19 @@ CONFIG_ATA_BMDMA=y
|
|||||||
#
|
#
|
||||||
# SATA SFF controllers with BMDMA
|
# SATA SFF controllers with BMDMA
|
||||||
#
|
#
|
||||||
CONFIG_ATA_PIIX=y
|
CONFIG_ATA_PIIX=m
|
||||||
CONFIG_SATA_DWC=y
|
CONFIG_SATA_DWC=m
|
||||||
# CONFIG_SATA_DWC_OLD_DMA is not set
|
# CONFIG_SATA_DWC_OLD_DMA is not set
|
||||||
CONFIG_SATA_MV=y
|
CONFIG_SATA_MV=m
|
||||||
CONFIG_SATA_NV=y
|
CONFIG_SATA_NV=m
|
||||||
CONFIG_SATA_PROMISE=y
|
CONFIG_SATA_PROMISE=m
|
||||||
CONFIG_SATA_RCAR=y
|
CONFIG_SATA_RCAR=m
|
||||||
CONFIG_SATA_SIL=y
|
CONFIG_SATA_SIL=m
|
||||||
CONFIG_SATA_SIS=y
|
CONFIG_SATA_SIS=m
|
||||||
CONFIG_SATA_SVW=y
|
CONFIG_SATA_SVW=m
|
||||||
CONFIG_SATA_ULI=y
|
CONFIG_SATA_ULI=m
|
||||||
CONFIG_SATA_VIA=y
|
CONFIG_SATA_VIA=m
|
||||||
CONFIG_SATA_VITESSE=y
|
CONFIG_SATA_VITESSE=m
|
||||||
|
|
||||||
#
|
#
|
||||||
# PATA SFF controllers with BMDMA
|
# PATA SFF controllers with BMDMA
|
||||||
@@ -3206,7 +3207,7 @@ CONFIG_PATA_RDC=m
|
|||||||
CONFIG_PATA_SCH=m
|
CONFIG_PATA_SCH=m
|
||||||
CONFIG_PATA_SERVERWORKS=m
|
CONFIG_PATA_SERVERWORKS=m
|
||||||
CONFIG_PATA_SIL680=m
|
CONFIG_PATA_SIL680=m
|
||||||
CONFIG_PATA_SIS=y
|
CONFIG_PATA_SIS=m
|
||||||
CONFIG_PATA_TOSHIBA=m
|
CONFIG_PATA_TOSHIBA=m
|
||||||
CONFIG_PATA_TRIFLEX=m
|
CONFIG_PATA_TRIFLEX=m
|
||||||
CONFIG_PATA_VIA=m
|
CONFIG_PATA_VIA=m
|
||||||
@@ -3248,8 +3249,8 @@ CONFIG_PATA_PARPORT_ON26=m
|
|||||||
#
|
#
|
||||||
# Generic fallback / legacy drivers
|
# Generic fallback / legacy drivers
|
||||||
#
|
#
|
||||||
CONFIG_PATA_ACPI=y
|
CONFIG_PATA_ACPI=m
|
||||||
CONFIG_ATA_GENERIC=y
|
CONFIG_ATA_GENERIC=m
|
||||||
CONFIG_PATA_LEGACY=m
|
CONFIG_PATA_LEGACY=m
|
||||||
CONFIG_MD=y
|
CONFIG_MD=y
|
||||||
CONFIG_BLK_DEV_MD=m
|
CONFIG_BLK_DEV_MD=m
|
||||||
@@ -10435,11 +10436,11 @@ CONFIG_VMGENID=m
|
|||||||
CONFIG_NITRO_ENCLAVES=m
|
CONFIG_NITRO_ENCLAVES=m
|
||||||
CONFIG_ARM_PKVM_GUEST=y
|
CONFIG_ARM_PKVM_GUEST=y
|
||||||
CONFIG_VIRTIO_ANCHOR=y
|
CONFIG_VIRTIO_ANCHOR=y
|
||||||
CONFIG_VIRTIO=y
|
CONFIG_VIRTIO=m
|
||||||
CONFIG_VIRTIO_PCI_LIB=y
|
CONFIG_VIRTIO_PCI_LIB=m
|
||||||
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
|
CONFIG_VIRTIO_PCI_LIB_LEGACY=m
|
||||||
CONFIG_VIRTIO_MENU=y
|
CONFIG_VIRTIO_MENU=y
|
||||||
CONFIG_VIRTIO_PCI=y
|
CONFIG_VIRTIO_PCI=m
|
||||||
CONFIG_VIRTIO_PCI_LEGACY=y
|
CONFIG_VIRTIO_PCI_LEGACY=y
|
||||||
CONFIG_VIRTIO_VDPA=m
|
CONFIG_VIRTIO_VDPA=m
|
||||||
CONFIG_VIRTIO_PMEM=m
|
CONFIG_VIRTIO_PMEM=m
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ func (t Toolchain) newKmod() (pkg.Artifact, string) {
|
|||||||
pkg.TarGzip,
|
pkg.TarGzip,
|
||||||
), nil, &MesonHelper{
|
), nil, &MesonHelper{
|
||||||
Setup: [][2]string{
|
Setup: [][2]string{
|
||||||
{"Dmoduledir", "/system/lib/modules"},
|
|
||||||
{"Dsysconfdir", "/system/etc"},
|
{"Dsysconfdir", "/system/etc"},
|
||||||
{"Dbashcompletiondir", "no"},
|
{"Dbashcompletiondir", "no"},
|
||||||
{"Dfishcompletiondir", "no"},
|
{"Dfishcompletiondir", "no"},
|
||||||
@@ -39,12 +38,6 @@ func init() {
|
|||||||
Description: "a set of tools to handle common tasks with Linux kernel modules",
|
Description: "a set of tools to handle common tasks with Linux kernel modules",
|
||||||
Website: "https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git",
|
Website: "https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zlib,
|
|
||||||
Zstd,
|
|
||||||
OpenSSL,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 1517,
|
ID: 1517,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ func init() {
|
|||||||
Description: "an open source code library for the dynamic creation of images",
|
Description: "an open source code library for the dynamic creation of images",
|
||||||
Website: "https://libgd.github.io/",
|
Website: "https://libgd.github.io/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zlib,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 880,
|
ID: 880,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ func (t Toolchain) newLibxslt() (pkg.Artifact, string) {
|
|||||||
SkipCheck: true,
|
SkipCheck: true,
|
||||||
},
|
},
|
||||||
XZ,
|
XZ,
|
||||||
|
Zlib,
|
||||||
Python,
|
Python,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
|
||||||
@@ -37,10 +38,6 @@ func init() {
|
|||||||
Description: "an XSLT processor based on libxml2",
|
Description: "an XSLT processor based on libxml2",
|
||||||
Website: "https://gitlab.gnome.org/GNOME/libxslt/",
|
Website: "https://gitlab.gnome.org/GNOME/libxslt/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Libxml2,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 13301,
|
ID: 13301,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,8 +73,14 @@ func llvmFlagName(flag int) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
llvmVersionMajor = "22"
|
||||||
|
llvmVersion = llvmVersionMajor + ".1.0"
|
||||||
|
)
|
||||||
|
|
||||||
// newLLVMVariant returns a [pkg.Artifact] containing a LLVM variant.
|
// newLLVMVariant returns a [pkg.Artifact] containing a LLVM variant.
|
||||||
func (t Toolchain) newLLVMVariant(variant string, attr *llvmAttr) pkg.Artifact {
|
func (t Toolchain) newLLVMVariant(variant string, attr *llvmAttr) pkg.Artifact {
|
||||||
|
const checksum = "-_Tu5Lt8xkWoxm2VDVV7crh0WqZQbbblN3fYamMdPTDSy_54FAkD2ii7afSymPVV"
|
||||||
|
|
||||||
if attr == nil {
|
if attr == nil {
|
||||||
panic("LLVM attr must be non-nil")
|
panic("LLVM attr must be non-nil")
|
||||||
@@ -119,8 +125,6 @@ func (t Toolchain) newLLVMVariant(variant string, attr *llvmAttr) pkg.Artifact {
|
|||||||
|
|
||||||
[2]string{"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"},
|
[2]string{"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"},
|
||||||
[2]string{"LLVM_INSTALL_CCTOOLS_SYMLINKS", "ON"},
|
[2]string{"LLVM_INSTALL_CCTOOLS_SYMLINKS", "ON"},
|
||||||
|
|
||||||
[2]string{"LLVM_LIT_ARGS", "'--verbose'"},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +167,7 @@ ln -s ld.lld /work/system/bin/ld
|
|||||||
return t.NewPackage("llvm", llvmVersion, pkg.NewHTTPGetTar(
|
return t.NewPackage("llvm", llvmVersion, pkg.NewHTTPGetTar(
|
||||||
nil, "https://github.com/llvm/llvm-project/archive/refs/tags/"+
|
nil, "https://github.com/llvm/llvm-project/archive/refs/tags/"+
|
||||||
"llvmorg-"+llvmVersion+".tar.gz",
|
"llvmorg-"+llvmVersion+".tar.gz",
|
||||||
mustDecode(llvmChecksum),
|
mustDecode(checksum),
|
||||||
pkg.TarGzip,
|
pkg.TarGzip,
|
||||||
), &PackageAttr{
|
), &PackageAttr{
|
||||||
Patches: attr.patches,
|
Patches: attr.patches,
|
||||||
@@ -183,6 +187,8 @@ ln -s ld.lld /work/system/bin/ld
|
|||||||
Append: cmakeAppend,
|
Append: cmakeAppend,
|
||||||
Script: script + attr.script,
|
Script: script + attr.script,
|
||||||
},
|
},
|
||||||
|
Zlib,
|
||||||
|
Libffi,
|
||||||
Python,
|
Python,
|
||||||
Perl,
|
Perl,
|
||||||
Diffutils,
|
Diffutils,
|
||||||
@@ -310,7 +316,7 @@ ln -s clang++ /work/system/bin/c++
|
|||||||
ninja check-all
|
ninja check-all
|
||||||
`,
|
`,
|
||||||
|
|
||||||
patches: slices.Concat([][2]string{
|
patches: [][2]string{
|
||||||
{"add-rosa-vendor", `diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
|
{"add-rosa-vendor", `diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
|
||||||
index 9c83abeeb3b1..5acfe5836a23 100644
|
index 9c83abeeb3b1..5acfe5836a23 100644
|
||||||
--- a/llvm/include/llvm/TargetParser/Triple.h
|
--- a/llvm/include/llvm/TargetParser/Triple.h
|
||||||
@@ -482,7 +488,7 @@ index 64324a3f8b01..15ce70b68217 100644
|
|||||||
"/System/Library/Frameworks"};
|
"/System/Library/Frameworks"};
|
||||||
|
|
||||||
`},
|
`},
|
||||||
}, clangPatches),
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
package rosa
|
|
||||||
|
|
||||||
// clangPatches are patches applied to the LLVM source tree for building clang.
|
|
||||||
var clangPatches [][2]string
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package rosa
|
|
||||||
|
|
||||||
// clangPatches are patches applied to the LLVM source tree for building clang.
|
|
||||||
var clangPatches [][2]string
|
|
||||||
|
|
||||||
// one version behind, latest fails 5 tests with 2 flaky on arm64
|
|
||||||
const (
|
|
||||||
llvmVersionMajor = "21"
|
|
||||||
llvmVersion = llvmVersionMajor + ".1.8"
|
|
||||||
|
|
||||||
llvmChecksum = "8SUpqDkcgwOPsqHVtmf9kXfFeVmjVxl4LMn-qSE1AI_Xoeju-9HaoPNGtidyxyka"
|
|
||||||
)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
//go:build !arm64
|
|
||||||
|
|
||||||
package rosa
|
|
||||||
|
|
||||||
// latest version of LLVM, conditional to temporarily avoid broken new releases
|
|
||||||
const (
|
|
||||||
llvmVersionMajor = "22"
|
|
||||||
llvmVersion = llvmVersionMajor + ".1.1"
|
|
||||||
|
|
||||||
llvmChecksum = "bQvV6D8AZvQykg7-uQb_saTbVavnSo1ykNJ3g57F5iE-evU3HuOYtcRnVIXTK76e"
|
|
||||||
)
|
|
||||||
@@ -38,13 +38,6 @@ func init() {
|
|||||||
Description: "an open source build system",
|
Description: "an open source build system",
|
||||||
Website: "https://mesonbuild.com/",
|
Website: "https://mesonbuild.com/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Python,
|
|
||||||
PkgConfig,
|
|
||||||
CMake,
|
|
||||||
Ninja,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 6472,
|
ID: 6472,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +66,15 @@ func (*MesonHelper) name(name, version string) string {
|
|||||||
|
|
||||||
// extra returns hardcoded meson runtime dependencies.
|
// extra returns hardcoded meson runtime dependencies.
|
||||||
func (*MesonHelper) extra(int) []PArtifact {
|
func (*MesonHelper) extra(int) []PArtifact {
|
||||||
return []PArtifact{Meson}
|
return []PArtifact{
|
||||||
|
Zlib,
|
||||||
|
Python,
|
||||||
|
Meson,
|
||||||
|
Ninja,
|
||||||
|
|
||||||
|
PkgConfig,
|
||||||
|
CMake,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wantsChmod returns false.
|
// wantsChmod returns false.
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ func (t Toolchain) newMuslFts() (pkg.Artifact, string) {
|
|||||||
}, &MakeHelper{
|
}, &MakeHelper{
|
||||||
Generate: "./bootstrap.sh",
|
Generate: "./bootstrap.sh",
|
||||||
},
|
},
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
|
Autoconf,
|
||||||
Automake,
|
Automake,
|
||||||
Libtool,
|
Libtool,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ func (t Toolchain) newMuslObstack() (pkg.Artifact, string) {
|
|||||||
}, &MakeHelper{
|
}, &MakeHelper{
|
||||||
Generate: "./bootstrap.sh",
|
Generate: "./bootstrap.sh",
|
||||||
},
|
},
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
|
Autoconf,
|
||||||
Automake,
|
Automake,
|
||||||
Libtool,
|
Libtool,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
|||||||
@@ -26,10 +26,6 @@ func init() {
|
|||||||
Description: "a low-level cryptographic library",
|
Description: "a low-level cryptographic library",
|
||||||
Website: "https://www.lysator.liu.se/~nisse/nettle/",
|
Website: "https://www.lysator.liu.se/~nisse/nettle/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
GMP,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 2073,
|
ID: 2073,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
func (t Toolchain) newPerl() (pkg.Artifact, string) {
|
func (t Toolchain) newPerl() (pkg.Artifact, string) {
|
||||||
const (
|
const (
|
||||||
version = "5.42.1"
|
version = "5.42.0"
|
||||||
checksum = "FsJVq5CZFA7nZklfUl1eC6z2ECEu02XaB1pqfHSKtRLZWpnaBjlB55QOhjKpjkQ2"
|
checksum = "2KR7Jbpk-ZVn1a30LQRwbgUvg2AXlPQZfzrqCr31qD5-yEsTwVQ_W76eZH-EdxM9"
|
||||||
)
|
)
|
||||||
return t.NewPackage("perl", version, pkg.NewHTTPGetTar(
|
return t.NewPackage("perl", version, pkg.NewHTTPGetTar(
|
||||||
nil, "https://www.cpan.org/src/5.0/perl-"+version+".tar.gz",
|
nil, "https://www.cpan.org/src/5.0/perl-"+version+".tar.gz",
|
||||||
@@ -68,14 +68,14 @@ func (t Toolchain) newViaPerlModuleBuild(
|
|||||||
name, version string,
|
name, version string,
|
||||||
source pkg.Artifact,
|
source pkg.Artifact,
|
||||||
patches [][2]string,
|
patches [][2]string,
|
||||||
extra ...PArtifact,
|
extra ...pkg.Artifact,
|
||||||
) pkg.Artifact {
|
) pkg.Artifact {
|
||||||
if name == "" || version == "" {
|
if name == "" || version == "" {
|
||||||
panic("names must be non-empty")
|
panic("names must be non-empty")
|
||||||
}
|
}
|
||||||
return t.New("perl-"+name, 0, t.AppendPresets(nil,
|
return t.New("perl-"+name, 0, slices.Concat(extra, []pkg.Artifact{
|
||||||
slices.Concat(P{Perl}, extra)...,
|
t.Load(Perl),
|
||||||
), nil, nil, `
|
}), nil, nil, `
|
||||||
cd /usr/src/`+name+`
|
cd /usr/src/`+name+`
|
||||||
perl Build.PL --prefix=/system
|
perl Build.PL --prefix=/system
|
||||||
./Build build
|
./Build build
|
||||||
@@ -105,10 +105,6 @@ func init() {
|
|||||||
Name: "perl-Module::Build",
|
Name: "perl-Module::Build",
|
||||||
Description: "build and install Perl modules",
|
Description: "build and install Perl modules",
|
||||||
Website: "https://metacpan.org/release/Module-Build",
|
Website: "https://metacpan.org/release/Module-Build",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Perl,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,10 +267,6 @@ func init() {
|
|||||||
Name: "perl-Text::WrapI18N",
|
Name: "perl-Text::WrapI18N",
|
||||||
Description: "line wrapping module",
|
Description: "line wrapping module",
|
||||||
Website: "https://metacpan.org/release/Text-WrapI18N",
|
Website: "https://metacpan.org/release/Text-WrapI18N",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
PerlTextCharWidth,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,10 +313,6 @@ func init() {
|
|||||||
Name: "perl-Unicode::GCString",
|
Name: "perl-Unicode::GCString",
|
||||||
Description: "String as Sequence of UAX #29 Grapheme Clusters",
|
Description: "String as Sequence of UAX #29 Grapheme Clusters",
|
||||||
Website: "https://metacpan.org/release/Unicode-LineBreak",
|
Website: "https://metacpan.org/release/Unicode-LineBreak",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
PerlMIMECharset,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ func (t Toolchain) newProcps() (pkg.Artifact, string) {
|
|||||||
{"without-ncurses"},
|
{"without-ncurses"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
|
Autoconf,
|
||||||
Automake,
|
Automake,
|
||||||
Gettext,
|
Gettext,
|
||||||
Libtool,
|
Libtool,
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ func (t Toolchain) newPython() (pkg.Artifact, string) {
|
|||||||
Check: []string{"test"},
|
Check: []string{"test"},
|
||||||
},
|
},
|
||||||
Zlib,
|
Zlib,
|
||||||
Bzip2,
|
|
||||||
Libffi,
|
Libffi,
|
||||||
OpenSSL,
|
|
||||||
|
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
OpenSSL,
|
||||||
|
Bzip2,
|
||||||
XZ,
|
XZ,
|
||||||
), version
|
), version
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,6 @@ func init() {
|
|||||||
Description: "the Python programming language interpreter",
|
Description: "the Python programming language interpreter",
|
||||||
Website: "https://www.python.org/",
|
Website: "https://www.python.org/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zlib,
|
|
||||||
Bzip2,
|
|
||||||
Libffi,
|
|
||||||
OpenSSL,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 13254,
|
ID: 13254,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,9 +81,15 @@ func newViaPip(
|
|||||||
wname := name + "-" + version + "-" + interpreter + "-" + abi + "-" + platform + ".whl"
|
wname := name + "-" + version + "-" + interpreter + "-" + abi + "-" + platform + ".whl"
|
||||||
return Metadata{
|
return Metadata{
|
||||||
f: func(t Toolchain) (pkg.Artifact, string) {
|
f: func(t Toolchain) (pkg.Artifact, string) {
|
||||||
return t.New(name+"-"+version, 0, t.AppendPresets(nil,
|
extraRes := make([]pkg.Artifact, len(extra))
|
||||||
slices.Concat(P{Python}, extra)...,
|
for i, p := range extra {
|
||||||
), nil, nil, `
|
extraRes[i] = t.Load(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.New(name+"-"+version, 0, slices.Concat([]pkg.Artifact{
|
||||||
|
t.Load(Zlib),
|
||||||
|
t.Load(Python),
|
||||||
|
}, extraRes), nil, nil, `
|
||||||
pip3 install \
|
pip3 install \
|
||||||
--no-index \
|
--no-index \
|
||||||
--prefix=/system \
|
--prefix=/system \
|
||||||
@@ -105,19 +104,18 @@ pip3 install \
|
|||||||
Name: "python-" + name,
|
Name: "python-" + name,
|
||||||
Description: description,
|
Description: description,
|
||||||
Website: "https://pypi.org/project/" + name + "/",
|
Website: "https://pypi.org/project/" + name + "/",
|
||||||
|
|
||||||
Dependencies: slices.Concat(P{Python}, extra),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Toolchain) newSetuptools() (pkg.Artifact, string) {
|
func (t Toolchain) newSetuptools() (pkg.Artifact, string) {
|
||||||
const (
|
const (
|
||||||
version = "82.0.1"
|
version = "82.0.0"
|
||||||
checksum = "nznP46Tj539yqswtOrIM4nQgwLA1h-ApKX7z7ghazROCpyF5swtQGwsZoI93wkhc"
|
checksum = "K9f8Yi7Gg95zjmQsE1LLw9UBb8NglI6EY6pQpdD6DM0Pmc_Td5w2qs1SMngTI6Jp"
|
||||||
)
|
)
|
||||||
return t.New("setuptools-"+version, 0, t.AppendPresets(nil,
|
return t.New("setuptools-"+version, 0, []pkg.Artifact{
|
||||||
Python,
|
t.Load(Zlib),
|
||||||
), nil, nil, `
|
t.Load(Python),
|
||||||
|
}, nil, nil, `
|
||||||
pip3 install \
|
pip3 install \
|
||||||
--no-index \
|
--no-index \
|
||||||
--prefix=/system \
|
--prefix=/system \
|
||||||
@@ -134,14 +132,10 @@ func init() {
|
|||||||
artifactsM[Setuptools] = Metadata{
|
artifactsM[Setuptools] = Metadata{
|
||||||
f: Toolchain.newSetuptools,
|
f: Toolchain.newSetuptools,
|
||||||
|
|
||||||
Name: "python-setuptools",
|
Name: "setuptools",
|
||||||
Description: "the autotools of the Python ecosystem",
|
Description: "the autotools of the Python ecosystem",
|
||||||
Website: "https://pypi.org/project/setuptools/",
|
Website: "https://pypi.org/project/setuptools/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Python,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 4021,
|
ID: 4021,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,6 +272,8 @@ func init() {
|
|||||||
"https://files.pythonhosted.org/packages/"+
|
"https://files.pythonhosted.org/packages/"+
|
||||||
"78/55/896b06bf93a49bec0f4ae2a6f1ed12bd05c8860744ac3a70eda041064e4d/",
|
"78/55/896b06bf93a49bec0f4ae2a6f1ed12bd05c8860744ac3a70eda041064e4d/",
|
||||||
PythonDistlib,
|
PythonDistlib,
|
||||||
|
PythonFilelock,
|
||||||
|
PythonPlatformdirs,
|
||||||
PythonDiscovery,
|
PythonDiscovery,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -292,6 +288,10 @@ func init() {
|
|||||||
PythonIdentify,
|
PythonIdentify,
|
||||||
PythonNodeenv,
|
PythonNodeenv,
|
||||||
PythonPyYAML,
|
PythonPyYAML,
|
||||||
|
PythonDistlib,
|
||||||
|
PythonFilelock,
|
||||||
|
PythonPlatformdirs,
|
||||||
|
PythonDiscovery,
|
||||||
PythonVirtualenv,
|
PythonVirtualenv,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,16 +74,21 @@ EOF
|
|||||||
Bash,
|
Bash,
|
||||||
Python,
|
Python,
|
||||||
Ninja,
|
Ninja,
|
||||||
|
Bzip2,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
Diffutils,
|
Diffutils,
|
||||||
|
|
||||||
OpenSSL,
|
OpenSSL,
|
||||||
|
Bzip2,
|
||||||
XZ,
|
XZ,
|
||||||
|
|
||||||
Flex,
|
Flex,
|
||||||
Bison,
|
Bison,
|
||||||
M4,
|
M4,
|
||||||
|
|
||||||
|
PCRE2,
|
||||||
|
Libffi,
|
||||||
|
Zlib,
|
||||||
GLib,
|
GLib,
|
||||||
Zstd,
|
Zstd,
|
||||||
DTC,
|
DTC,
|
||||||
@@ -98,11 +103,6 @@ func init() {
|
|||||||
Description: "a generic and open source machine emulator and virtualizer",
|
Description: "a generic and open source machine emulator and virtualizer",
|
||||||
Website: "https://www.qemu.org/",
|
Website: "https://www.qemu.org/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
GLib,
|
|
||||||
Zstd,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 13607,
|
ID: 13607,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,6 @@ func init() {
|
|||||||
Description: "a program that finds duplicate files",
|
Description: "a program that finds duplicate files",
|
||||||
Website: "https://rdfind.pauldreik.se/",
|
Website: "https://rdfind.pauldreik.se/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Nettle,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 231641,
|
ID: 231641,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
@@ -20,9 +19,6 @@ const (
|
|||||||
|
|
||||||
// kindBusyboxBin is the kind of [pkg.Artifact] of busyboxBin.
|
// kindBusyboxBin is the kind of [pkg.Artifact] of busyboxBin.
|
||||||
kindBusyboxBin
|
kindBusyboxBin
|
||||||
|
|
||||||
// kindCollection is the kind of [Collect]. It never cures successfully.
|
|
||||||
kindCollection
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// mustDecode is like [pkg.MustDecode], but replaces the zero value and prints
|
// mustDecode is like [pkg.MustDecode], but replaces the zero value and prints
|
||||||
@@ -458,48 +454,6 @@ type PackageAttr struct {
|
|||||||
Flag int
|
Flag int
|
||||||
}
|
}
|
||||||
|
|
||||||
// pa holds whether a [PArtifact] is present.
|
|
||||||
type pa = [PresetEnd]bool
|
|
||||||
|
|
||||||
// paPool holds addresses of pa.
|
|
||||||
var paPool = sync.Pool{New: func() any { return new(pa) }}
|
|
||||||
|
|
||||||
// paGet returns the address of a new pa.
|
|
||||||
func paGet() *pa { return paPool.Get().(*pa) }
|
|
||||||
|
|
||||||
// paPut returns a pa to paPool.
|
|
||||||
func paPut(pv *pa) { *pv = pa{}; paPool.Put(pv) }
|
|
||||||
|
|
||||||
// appendPreset recursively appends a [PArtifact] and its runtime dependencies.
|
|
||||||
func (t Toolchain) appendPreset(
|
|
||||||
a []pkg.Artifact,
|
|
||||||
pv *pa, p PArtifact,
|
|
||||||
) []pkg.Artifact {
|
|
||||||
if pv[p] {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
pv[p] = true
|
|
||||||
|
|
||||||
for _, d := range GetMetadata(p).Dependencies {
|
|
||||||
a = t.appendPreset(a, pv, d)
|
|
||||||
}
|
|
||||||
return append(a, t.Load(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendPresets recursively appends multiple [PArtifact] and their runtime
|
|
||||||
// dependencies.
|
|
||||||
func (t Toolchain) AppendPresets(
|
|
||||||
a []pkg.Artifact,
|
|
||||||
presets ...PArtifact,
|
|
||||||
) []pkg.Artifact {
|
|
||||||
pv := paGet()
|
|
||||||
for _, p := range presets {
|
|
||||||
a = t.appendPreset(a, pv, p)
|
|
||||||
}
|
|
||||||
paPut(pv)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPackage constructs a [pkg.Artifact] via a build system helper.
|
// NewPackage constructs a [pkg.Artifact] via a build system helper.
|
||||||
func (t Toolchain) NewPackage(
|
func (t Toolchain) NewPackage(
|
||||||
name, version string,
|
name, version string,
|
||||||
@@ -532,14 +486,12 @@ func (t Toolchain) NewPackage(
|
|||||||
extraRes := make([]pkg.Artifact, 0, dc)
|
extraRes := make([]pkg.Artifact, 0, dc)
|
||||||
extraRes = append(extraRes, attr.NonStage0...)
|
extraRes = append(extraRes, attr.NonStage0...)
|
||||||
if !t.isStage0() {
|
if !t.isStage0() {
|
||||||
pv := paGet()
|
|
||||||
for _, p := range helper.extra(attr.Flag) {
|
for _, p := range helper.extra(attr.Flag) {
|
||||||
extraRes = t.appendPreset(extraRes, pv, p)
|
extraRes = append(extraRes, t.Load(p))
|
||||||
}
|
}
|
||||||
for _, p := range extra {
|
for _, p := range extra {
|
||||||
extraRes = t.appendPreset(extraRes, pv, p)
|
extraRes = append(extraRes, t.Load(p))
|
||||||
}
|
}
|
||||||
paPut(pv)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var scriptEarly string
|
var scriptEarly string
|
||||||
@@ -591,29 +543,3 @@ cd '/usr/src/` + name + `/'
|
|||||||
})...,
|
})...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collected is returned by [Collect.Cure] to indicate a successful collection.
|
|
||||||
type Collected struct{}
|
|
||||||
|
|
||||||
// Error returns a constant string to satisfy error, but should never be seen
|
|
||||||
// by the user.
|
|
||||||
func (Collected) Error() string { return "artifacts successfully collected" }
|
|
||||||
|
|
||||||
// Collect implements [pkg.FloodArtifact] to concurrently cure multiple
|
|
||||||
// [pkg.Artifact]. It returns [Collected].
|
|
||||||
type Collect []pkg.Artifact
|
|
||||||
|
|
||||||
// Cure returns [Collected].
|
|
||||||
func (*Collect) Cure(*pkg.FContext) error { return Collected{} }
|
|
||||||
|
|
||||||
// Kind returns the hardcoded [pkg.Kind] value.
|
|
||||||
func (*Collect) Kind() pkg.Kind { return kindCollection }
|
|
||||||
|
|
||||||
// Params does not write anything, dependencies are already represented in the header.
|
|
||||||
func (*Collect) Params(*pkg.IContext) {}
|
|
||||||
|
|
||||||
// Dependencies returns [Collect] as is.
|
|
||||||
func (c *Collect) Dependencies() []pkg.Artifact { return *c }
|
|
||||||
|
|
||||||
// IsExclusive returns false: Cure is a noop.
|
|
||||||
func (*Collect) IsExclusive() bool { return false }
|
|
||||||
|
|||||||
@@ -48,12 +48,6 @@ func init() {
|
|||||||
Description: "tools to create and extract Squashfs filesystems",
|
Description: "tools to create and extract Squashfs filesystems",
|
||||||
Website: "https://github.com/plougher/squashfs-tools",
|
Website: "https://github.com/plougher/squashfs-tools",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zstd,
|
|
||||||
Gzip,
|
|
||||||
Zlib,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 4879,
|
ID: 4879,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,10 +75,6 @@ func init() {
|
|||||||
Description: "Network Security Services",
|
Description: "Network Security Services",
|
||||||
Website: "https://firefox-source-docs.mozilla.org/security/nss/index.html",
|
Website: "https://firefox-source-docs.mozilla.org/security/nss/index.html",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Zlib,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 2503,
|
ID: 2503,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,12 +92,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t Toolchain) newNSSCACert() (pkg.Artifact, string) {
|
func (t Toolchain) newNSSCACert() (pkg.Artifact, string) {
|
||||||
return t.New("nss-cacert", 0, t.AppendPresets(nil,
|
return t.New("nss-cacert", 0, []pkg.Artifact{
|
||||||
Bash,
|
t.Load(Zlib),
|
||||||
|
t.Load(Bash),
|
||||||
|
t.Load(Python),
|
||||||
|
|
||||||
NSS,
|
t.Load(NSS),
|
||||||
buildcatrust,
|
t.Load(buildcatrust),
|
||||||
), nil, nil, `
|
}, nil, nil, `
|
||||||
mkdir -p /work/system/etc/ssl/{certs/unbundled,certs/hashed,trust-source}
|
mkdir -p /work/system/etc/ssl/{certs/unbundled,certs/hashed,trust-source}
|
||||||
buildcatrust \
|
buildcatrust \
|
||||||
--certdata_input /system/nss/certdata.txt \
|
--certdata_input /system/nss/certdata.txt \
|
||||||
@@ -8,13 +8,13 @@ import (
|
|||||||
|
|
||||||
func (t Toolchain) newTamaGo() (pkg.Artifact, string) {
|
func (t Toolchain) newTamaGo() (pkg.Artifact, string) {
|
||||||
const (
|
const (
|
||||||
version = "1.26.1"
|
version = "1.26.0"
|
||||||
checksum = "fimZnklQcYWGsTQU8KepLn-yCYaTfNdMI9DCg6NJVQv-3gOJnUEO9mqRCMAHnEXZ"
|
checksum = "5XkfbpTpSdPJfwtTfUegfdu4LUy8nuZ7sCondiRIxTJI9eQONi8z_O_dq9yDkjw8"
|
||||||
)
|
)
|
||||||
return t.New("tamago-go"+version, 0, t.AppendPresets(nil,
|
return t.New("tamago-go"+version, 0, []pkg.Artifact{
|
||||||
Bash,
|
t.Load(Bash),
|
||||||
Go,
|
t.Load(Go),
|
||||||
), nil, []string{
|
}, nil, []string{
|
||||||
"CC=cc",
|
"CC=cc",
|
||||||
"GOCACHE=/tmp/gocache",
|
"GOCACHE=/tmp/gocache",
|
||||||
}, `
|
}, `
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ func (t Toolchain) newUnzip() (pkg.Artifact, string) {
|
|||||||
version = "6.0"
|
version = "6.0"
|
||||||
checksum = "fcqjB1IOVRNJ16K5gTGEDt3zCJDVBc7EDSra9w3H93stqkNwH1vaPQs_QGOpQZu1"
|
checksum = "fcqjB1IOVRNJ16K5gTGEDt3zCJDVBc7EDSra9w3H93stqkNwH1vaPQs_QGOpQZu1"
|
||||||
)
|
)
|
||||||
return t.New("unzip-"+version, 0, t.AppendPresets(nil,
|
return t.New("unzip-"+version, 0, []pkg.Artifact{
|
||||||
Make,
|
t.Load(Make),
|
||||||
Coreutils,
|
t.Load(Coreutils),
|
||||||
), nil, nil, `
|
}, nil, nil, `
|
||||||
cd /usr/src/unzip/
|
cd /usr/src/unzip/
|
||||||
unix/configure
|
unix/configure
|
||||||
make -f unix/Makefile generic1
|
make -f unix/Makefile generic1
|
||||||
|
|||||||
@@ -42,12 +42,6 @@ func init() {
|
|||||||
Description: "core Wayland window system code and protocol",
|
Description: "core Wayland window system code and protocol",
|
||||||
Website: "https://wayland.freedesktop.org/",
|
Website: "https://wayland.freedesktop.org/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Libffi,
|
|
||||||
Libexpat,
|
|
||||||
Libxml2,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 10061,
|
ID: 10061,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,6 +112,9 @@ GitLab
|
|||||||
},
|
},
|
||||||
}, (*MesonHelper)(nil),
|
}, (*MesonHelper)(nil),
|
||||||
Wayland,
|
Wayland,
|
||||||
|
Libffi,
|
||||||
|
Libexpat,
|
||||||
|
Libxml2,
|
||||||
), version
|
), version
|
||||||
}
|
}
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ func (t Toolchain) newXproto() (pkg.Artifact, string) {
|
|||||||
// ancient configure script
|
// ancient configure script
|
||||||
Generate: "autoreconf -if",
|
Generate: "autoreconf -if",
|
||||||
},
|
},
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
|
Autoconf,
|
||||||
Automake,
|
Automake,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
|
||||||
@@ -72,6 +75,9 @@ func (t Toolchain) newLibXau() (pkg.Artifact, string) {
|
|||||||
// ancient configure script
|
// ancient configure script
|
||||||
Generate: "autoreconf -if",
|
Generate: "autoreconf -if",
|
||||||
},
|
},
|
||||||
|
M4,
|
||||||
|
Perl,
|
||||||
|
Autoconf,
|
||||||
Automake,
|
Automake,
|
||||||
Libtool,
|
Libtool,
|
||||||
PkgConfig,
|
PkgConfig,
|
||||||
@@ -88,10 +94,6 @@ func init() {
|
|||||||
Description: "functions for handling Xauthority files and entries",
|
Description: "functions for handling Xauthority files and entries",
|
||||||
Website: "https://gitlab.freedesktop.org/xorg/lib/libxau",
|
Website: "https://gitlab.freedesktop.org/xorg/lib/libxau",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
Xproto,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 1765,
|
ID: 1765,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ func (t Toolchain) newXCB() (pkg.Artifact, string) {
|
|||||||
PkgConfig,
|
PkgConfig,
|
||||||
|
|
||||||
XCBProto,
|
XCBProto,
|
||||||
|
Xproto,
|
||||||
LibXau,
|
LibXau,
|
||||||
), version
|
), version
|
||||||
}
|
}
|
||||||
@@ -52,11 +53,6 @@ func init() {
|
|||||||
Description: "The X protocol C-language Binding",
|
Description: "The X protocol C-language Binding",
|
||||||
Website: "https://xcb.freedesktop.org/",
|
Website: "https://xcb.freedesktop.org/",
|
||||||
|
|
||||||
Dependencies: P{
|
|
||||||
XCBProto,
|
|
||||||
LibXau,
|
|
||||||
},
|
|
||||||
|
|
||||||
ID: 1767,
|
ID: 1767,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,8 +139,6 @@ in
|
|||||||
inherit (app) identity groups enablements;
|
inherit (app) identity groups enablements;
|
||||||
inherit (dbusConfig) session_bus system_bus;
|
inherit (dbusConfig) session_bus system_bus;
|
||||||
direct_wayland = app.insecureWayland;
|
direct_wayland = app.insecureWayland;
|
||||||
sched_policy = app.schedPolicy;
|
|
||||||
sched_priority = app.schedPriority;
|
|
||||||
|
|
||||||
container = {
|
container = {
|
||||||
inherit (app)
|
inherit (app)
|
||||||
|
|||||||
24
options.nix
24
options.nix
@@ -98,7 +98,6 @@ in
|
|||||||
ints
|
ints
|
||||||
str
|
str
|
||||||
bool
|
bool
|
||||||
enum
|
|
||||||
package
|
package
|
||||||
anything
|
anything
|
||||||
submodule
|
submodule
|
||||||
@@ -238,29 +237,6 @@ in
|
|||||||
};
|
};
|
||||||
hostAbstract = mkEnableOption "share abstract unix socket scope";
|
hostAbstract = mkEnableOption "share abstract unix socket scope";
|
||||||
|
|
||||||
schedPolicy = mkOption {
|
|
||||||
type = nullOr (enum [
|
|
||||||
"fifo"
|
|
||||||
"rr"
|
|
||||||
"batch"
|
|
||||||
"idle"
|
|
||||||
"deadline"
|
|
||||||
"ext"
|
|
||||||
]);
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Scheduling policy to set for the container.
|
|
||||||
The zero value retains the current scheduling policy.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
schedPriority = mkOption {
|
|
||||||
type = nullOr (ints.between 1 99);
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Scheduling priority to set for the container.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
nix = mkEnableOption "nix daemon access";
|
nix = mkEnableOption "nix daemon access";
|
||||||
mapRealUid = mkEnableOption "mapping to priv-user uid";
|
mapRealUid = mkEnableOption "mapping to priv-user uid";
|
||||||
device = mkEnableOption "access to all devices";
|
device = mkEnableOption "access to all devices";
|
||||||
|
|||||||
36
package.nix
36
package.nix
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
stdenv,
|
stdenv,
|
||||||
buildGo126Module,
|
buildGoModule,
|
||||||
makeBinaryWrapper,
|
makeBinaryWrapper,
|
||||||
xdg-dbus-proxy,
|
xdg-dbus-proxy,
|
||||||
pkg-config,
|
pkg-config,
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
fuse3,
|
fuse3,
|
||||||
|
|
||||||
# for passthru.buildInputs
|
# for passthru.buildInputs
|
||||||
go_1_26,
|
go,
|
||||||
clang,
|
clang,
|
||||||
|
|
||||||
# for check
|
# for check
|
||||||
@@ -28,9 +28,9 @@
|
|||||||
withStatic ? stdenv.hostPlatform.isStatic,
|
withStatic ? stdenv.hostPlatform.isStatic,
|
||||||
}:
|
}:
|
||||||
|
|
||||||
buildGo126Module rec {
|
buildGoModule rec {
|
||||||
pname = "hakurei";
|
pname = "hakurei";
|
||||||
version = "0.3.7";
|
version = "0.3.6";
|
||||||
|
|
||||||
srcFiltered = builtins.path {
|
srcFiltered = builtins.path {
|
||||||
name = "${pname}-src";
|
name = "${pname}-src";
|
||||||
@@ -51,7 +51,7 @@ buildGo126Module rec {
|
|||||||
];
|
];
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
go_1_26
|
go
|
||||||
pkg-config
|
pkg-config
|
||||||
wayland-scanner
|
wayland-scanner
|
||||||
];
|
];
|
||||||
@@ -125,20 +125,16 @@ buildGo126Module rec {
|
|||||||
--inherit-argv0 --prefix PATH : ${lib.makeBinPath appPackages}
|
--inherit-argv0 --prefix PATH : ${lib.makeBinPath appPackages}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
passthru = {
|
passthru.targetPkgs = [
|
||||||
go = go_1_26;
|
go
|
||||||
|
clang
|
||||||
|
xorg.xorgproto
|
||||||
|
util-linux
|
||||||
|
|
||||||
targetPkgs = [
|
# for go generate
|
||||||
go_1_26
|
wayland-protocols
|
||||||
clang
|
wayland-scanner
|
||||||
xorg.xorgproto
|
]
|
||||||
util-linux
|
++ buildInputs
|
||||||
|
++ nativeBuildInputs;
|
||||||
# for go generate
|
|
||||||
wayland-protocols
|
|
||||||
wayland-scanner
|
|
||||||
]
|
|
||||||
++ buildInputs
|
|
||||||
++ nativeBuildInputs;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,15 +28,6 @@
|
|||||||
# Automatically login on tty1 as a normal user:
|
# Automatically login on tty1 as a normal user:
|
||||||
services.getty.autologinUser = "alice";
|
services.getty.autologinUser = "alice";
|
||||||
|
|
||||||
security.pam.loginLimits = [
|
|
||||||
{
|
|
||||||
domain = "@users";
|
|
||||||
item = "rtprio";
|
|
||||||
type = "-";
|
|
||||||
value = 1;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
systemPackages = with pkgs; [
|
systemPackages = with pkgs; [
|
||||||
# For D-Bus tests:
|
# For D-Bus tests:
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ testers.nixosTest {
|
|||||||
(writeShellScriptBin "hakurei-test" ''
|
(writeShellScriptBin "hakurei-test" ''
|
||||||
# Assert hst CGO_ENABLED=0: ${
|
# Assert hst CGO_ENABLED=0: ${
|
||||||
with pkgs;
|
with pkgs;
|
||||||
runCommand "hakurei-hst-cgo" { nativeBuildInputs = [ self.packages.${system}.hakurei.go ]; } ''
|
runCommand "hakurei-hst-cgo" { nativeBuildInputs = [ go ]; } ''
|
||||||
cp -r ${options.environment.hakurei.package.default.src} "$out"
|
cp -r ${options.environment.hakurei.package.default.src} "$out"
|
||||||
chmod -R +w "$out"
|
chmod -R +w "$out"
|
||||||
cp ${writeText "hst_cgo_test.go" ''package hakurei_test;import("testing";"hakurei.app/hst");func TestTemplate(t *testing.T){hst.Template()}''} "$out/hst_cgo_test.go"
|
cp ${writeText "hst_cgo_test.go" ''package hakurei_test;import("testing";"hakurei.app/hst");func TestTemplate(t *testing.T){hst.Template()}''} "$out/hst_cgo_test.go"
|
||||||
|
|||||||
@@ -23,14 +23,6 @@
|
|||||||
security = {
|
security = {
|
||||||
sudo.wheelNeedsPassword = false;
|
sudo.wheelNeedsPassword = false;
|
||||||
rtkit.enable = true;
|
rtkit.enable = true;
|
||||||
pam.loginLimits = [
|
|
||||||
{
|
|
||||||
domain = "@users";
|
|
||||||
item = "rtprio";
|
|
||||||
type = "-";
|
|
||||||
value = 1;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
|||||||
11
test/test.py
11
test/test.py
@@ -206,17 +206,6 @@ machine.wait_until_fails("pgrep foot", timeout=5)
|
|||||||
machine.wait_for_file("/tmp/shim-cont-unexpected-pid")
|
machine.wait_for_file("/tmp/shim-cont-unexpected-pid")
|
||||||
print(machine.succeed('grep "shim: got SIGCONT from unexpected process$" /tmp/shim-cont-unexpected-pid'))
|
print(machine.succeed('grep "shim: got SIGCONT from unexpected process$" /tmp/shim-cont-unexpected-pid'))
|
||||||
|
|
||||||
# Check setscheduler:
|
|
||||||
sched_unset = int(machine.succeed("sudo -u alice -i hakurei -v run cat /proc/self/sched | grep '^policy' | tr -d ' ' | cut -d ':' -f 2"))
|
|
||||||
if sched_unset != 0:
|
|
||||||
raise Exception(f"unexpected unset policy: {sched_unset}")
|
|
||||||
sched_idle = int(machine.succeed("sudo -u alice -i hakurei -v run --policy=idle cat /proc/self/sched | grep '^policy' | tr -d ' ' | cut -d ':' -f 2"))
|
|
||||||
if sched_idle != 5:
|
|
||||||
raise Exception(f"unexpected idle policy: {sched_idle}")
|
|
||||||
sched_rr = int(machine.succeed("sudo -u alice -i hakurei -v run --policy=rr cat /proc/self/sched | grep '^policy' | tr -d ' ' | cut -d ':' -f 2"))
|
|
||||||
if sched_rr != 2:
|
|
||||||
raise Exception(f"unexpected round-robin policy: {sched_idle}")
|
|
||||||
|
|
||||||
# Start app (foot) with Wayland enablement:
|
# Start app (foot) with Wayland enablement:
|
||||||
swaymsg("exec ne-foot")
|
swaymsg("exec ne-foot")
|
||||||
wait_for_window(f"u0_a{hakurei_identity(0)}@machine")
|
wait_for_window(f"u0_a{hakurei_identity(0)}@machine")
|
||||||
|
|||||||
Reference in New Issue
Block a user