19 Commits

Author SHA1 Message Date
08c35ca24f container: use new netlink implementation
This is adapted from the container netlink implementation and is much more reusable.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 23:33:52 +09:00
72bd3fb05e internal/netlink: generalise implementation from container
This is useful for uevent implementation.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 23:07:51 +09:00
59c66747df internal/rosa/kernel: 6.12.76 to 6.12.77
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 15:21:33 +09:00
9e6fe8db4b internal/rosa/meson: 1.10.1 to 1.10.2
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 13:41:06 +09:00
5168ee3e13 internal/rosa/python: remove pre_commit
This is unused and introduces many dependencies.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 13:39:56 +09:00
c8313c2dc4 internal/rosa/tamago: disable cgo
This toolchain does not support cgo for the new target, anyway, and disabling it altogether avoids adding a dependency on arm64.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 13:22:10 +09:00
3fcdadb669 internal/rosa/curl: remove broken test
Upstream testdata is not broken on the arm64 builder, but breaks reproducibly on amd64.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-16 12:54:03 +09:00
3966bc5152 internal/rosa/hakurei: 0.3.6 to 0.3.7
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-15 21:43:55 +09:00
b208af8b85 release: 0.3.7
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-15 21:04:55 +09:00
8d650c0c8f all: migrate to rosa/hakurei
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-15 20:12:51 +09:00
a720efc32d internal/rosa/llvm: arch-specific versions
This enables temporarily avoiding a broken release on specific targets.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-15 15:06:36 +09:00
400540cd41 internal/rosa/llvm: arch-specific patches
Broken aarch64 tests in LLVM seem unlikely to be fixed soon.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-15 11:37:24 +09:00
1113efa5c2 internal/rosa/kernel: enable arm64 block drivers
These are added separately to the amd64 patch due to the arm64 toolchain not being available at that time.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-15 00:22:05 +09:00
8b875f865c cmd/earlyinit: remount root and set firmware path
The default search paths cannot be configured, configuring them here is most sound for now.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-14 19:50:04 +09:00
8905d653ba cmd/earlyinit: mount pseudo-filesystems
The proposal for merging both init programs was unanimously accepted, so this is set up here alongside devtmpfs.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-14 19:43:42 +09:00
9c2fb6246f internal/rosa/kernel: enable FW_LOADER
This wants to be loaded early, so having it as a dlkm is not helpful as it will always be loaded anyway.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-14 19:32:14 +09:00
9c116acec6 internal/rosa/kernel: enable amd64 block drivers
These have to be built into initramfs, anyway, so build them into the kernel instead. The arm64 toolchain is not yet ready, so will be updated in a later patch.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-14 19:22:56 +09:00
988239a2bc internal/rosa: basic system image
This is a simple image for debugging and is not yet set up for dm-verity.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-14 15:54:13 +09:00
bc03118142 cmd/earlyinit: handle args from cmdline
These are set by the bootloader.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-03-14 15:13:52 +09:00
25 changed files with 708 additions and 595 deletions

View File

@@ -1,5 +1,5 @@
<p align="center">
<a href="https://git.gensokyo.uk/security/hakurei">
<a href="https://git.gensokyo.uk/rosa/hakurei">
<picture>
<img src="https://basement.gensokyo.uk/images/yukari1.png" width="200px" alt="Yukari">
</picture>
@@ -8,16 +8,16 @@
<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://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>
<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>
<br/>
<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://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://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>
</p>
Hakurei is a tool for running sandboxed desktop applications as dedicated
subordinate users on the Linux kernel. It implements the application container
of [planterette (WIP)](https://git.gensokyo.uk/security/planterette), a
of [planterette (WIP)](https://git.gensokyo.uk/rosa/planterette), a
self-contained Android-like package manager with modern security features.
Interaction with hakurei happens entirely through structures described by
@@ -62,4 +62,4 @@ are very likely to be rejected.
## NixOS Module (deprecated)
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).

View File

@@ -4,6 +4,7 @@ import (
"log"
"os"
"runtime"
"strings"
. "syscall"
)
@@ -12,6 +13,22 @@ func main() {
log.SetFlags(0)
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(
"devtmpfs",
"/dev/",
@@ -55,4 +72,56 @@ 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)
}
}

View File

@@ -3,6 +3,7 @@ package container
import (
"io"
"io/fs"
"net"
"os"
"os/exec"
"os/signal"
@@ -12,6 +13,7 @@ import (
"hakurei.app/container/seccomp"
"hakurei.app/container/std"
"hakurei.app/internal/netlink"
"hakurei.app/message"
)
@@ -167,7 +169,47 @@ func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm
func (direct) ensureFile(name string, perm, pperm os.FileMode) error {
return ensureFile(name, perm, pperm)
}
func (direct) mustLoopback(msg message.Msg) { mustLoopback(msg) }
func (direct) mustLoopback(msg message.Msg) {
var lo int
if ifi, err := net.InterfaceByName("lo"); err != nil {
msg.GetLogger().Fatalln(err)
} else {
lo = ifi.Index
}
c, err := netlink.DialRoute()
if err != nil {
msg.GetLogger().Fatalln(err)
}
must := func(err error) {
if err == nil {
return
}
if closeErr := c.Close(); closeErr != nil {
msg.Verbosef("cannot close RTNETLINK: %v", closeErr)
}
switch err.(type) {
case *os.SyscallError:
msg.GetLogger().Fatalf("cannot %v", err)
case syscall.Errno:
msg.GetLogger().Fatalf("RTNETLINK answers: %v", err)
default:
msg.GetLogger().Fatalf("RTNETLINK answers with malformed message")
}
}
must(c.SendNewaddrLo(uint32(lo)))
must(c.SendIfInfomsg(syscall.RTM_NEWLINK, 0, &syscall.IfInfomsg{
Family: syscall.AF_UNSPEC,
Index: int32(lo),
Flags: syscall.IFF_UP,
Change: syscall.IFF_UP,
}))
must(c.Close())
}
func (direct) seccompLoad(rules []std.NativeRule, flags seccomp.ExportFlag) error {
return seccomp.Load(rules, flags)

View File

@@ -1,269 +0,0 @@
package container
import (
"encoding/binary"
"errors"
"net"
"os"
. "syscall"
"unsafe"
"hakurei.app/container/std"
"hakurei.app/message"
)
// rtnetlink represents a NETLINK_ROUTE socket.
type rtnetlink struct {
// Sent as part of rtnetlink messages.
pid uint32
// AF_NETLINK socket.
fd int
// Whether the socket is open.
ok bool
// Message sequence number.
seq uint32
}
// open creates the underlying NETLINK_ROUTE socket.
func (s *rtnetlink) open() (err error) {
if s.ok || s.fd < 0 {
return os.ErrInvalid
}
s.pid = uint32(Getpid())
if s.fd, err = Socket(
AF_NETLINK,
SOCK_RAW|SOCK_CLOEXEC,
NETLINK_ROUTE,
); err != nil {
return os.NewSyscallError("socket", err)
} else if err = Bind(s.fd, &SockaddrNetlink{
Family: AF_NETLINK,
Pid: s.pid,
}); err != nil {
_ = s.close()
return os.NewSyscallError("bind", err)
} else {
s.ok = true
return nil
}
}
// close closes the underlying NETLINK_ROUTE socket.
func (s *rtnetlink) close() error {
if !s.ok {
return os.ErrInvalid
}
s.ok = false
err := Close(s.fd)
s.fd = -1
return err
}
// roundtrip sends a netlink message and handles the reply.
func (s *rtnetlink) roundtrip(data []byte) error {
if !s.ok {
return os.ErrInvalid
}
defer func() { s.seq++ }()
if err := Sendto(s.fd, data, 0, &SockaddrNetlink{
Family: AF_NETLINK,
}); err != nil {
return os.NewSyscallError("sendto", err)
}
buf := make([]byte, Getpagesize())
done:
for {
p := buf
if n, _, err := Recvfrom(s.fd, p, 0); err != nil {
return os.NewSyscallError("recvfrom", err)
} else if n < NLMSG_HDRLEN {
return errors.ErrUnsupported
} else {
p = p[:n]
}
if msgs, err := ParseNetlinkMessage(p); err != nil {
return err
} else {
for _, m := range msgs {
if m.Header.Seq != s.seq || m.Header.Pid != s.pid {
return errors.ErrUnsupported
}
if m.Header.Type == NLMSG_DONE {
break done
}
if m.Header.Type == NLMSG_ERROR {
if len(m.Data) >= 4 {
errno := Errno(-std.Int(binary.NativeEndian.Uint32(m.Data)))
if errno == 0 {
return nil
}
return errno
}
return errors.ErrUnsupported
}
}
}
}
return nil
}
// mustRoundtrip calls roundtrip and terminates via msg for a non-nil error.
func (s *rtnetlink) mustRoundtrip(msg message.Msg, data []byte) {
err := s.roundtrip(data)
if err == nil {
return
}
if closeErr := Close(s.fd); closeErr != nil {
msg.Verbosef("cannot close: %v", err)
}
switch err.(type) {
case *os.SyscallError:
msg.GetLogger().Fatalf("cannot %v", err)
case Errno:
msg.GetLogger().Fatalf("RTNETLINK answers: %v", err)
default:
msg.GetLogger().Fatalln("RTNETLINK answers with unexpected message")
}
}
// newaddrLo represents a RTM_NEWADDR message with two addresses.
type newaddrLo struct {
header NlMsghdr
data IfAddrmsg
r0 RtAttr
a0 [4]byte // in_addr
r1 RtAttr
a1 [4]byte // in_addr
}
// sizeofNewaddrLo is the expected size of newaddrLo.
const sizeofNewaddrLo = NLMSG_HDRLEN + SizeofIfAddrmsg + (SizeofRtAttr+4)*2
// newaddrLo returns the address of a populated newaddrLo.
func (s *rtnetlink) newaddrLo(lo int) *newaddrLo {
return &newaddrLo{NlMsghdr{
Len: sizeofNewaddrLo,
Type: RTM_NEWADDR,
Flags: NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL,
Seq: s.seq,
Pid: s.pid,
}, IfAddrmsg{
Family: AF_INET,
Prefixlen: 8,
Flags: IFA_F_PERMANENT,
Scope: RT_SCOPE_HOST,
Index: uint32(lo),
}, RtAttr{
Len: uint16(SizeofRtAttr + len(newaddrLo{}.a0)),
Type: IFA_LOCAL,
}, [4]byte{127, 0, 0, 1}, RtAttr{
Len: uint16(SizeofRtAttr + len(newaddrLo{}.a1)),
Type: IFA_ADDRESS,
}, [4]byte{127, 0, 0, 1}}
}
func (msg *newaddrLo) toWireFormat() []byte {
var buf [sizeofNewaddrLo]byte
*(*uint32)(unsafe.Pointer(&buf[0:4][0])) = msg.header.Len
*(*uint16)(unsafe.Pointer(&buf[4:6][0])) = msg.header.Type
*(*uint16)(unsafe.Pointer(&buf[6:8][0])) = msg.header.Flags
*(*uint32)(unsafe.Pointer(&buf[8:12][0])) = msg.header.Seq
*(*uint32)(unsafe.Pointer(&buf[12:16][0])) = msg.header.Pid
buf[16] = msg.data.Family
buf[17] = msg.data.Prefixlen
buf[18] = msg.data.Flags
buf[19] = msg.data.Scope
*(*uint32)(unsafe.Pointer(&buf[20:24][0])) = msg.data.Index
*(*uint16)(unsafe.Pointer(&buf[24:26][0])) = msg.r0.Len
*(*uint16)(unsafe.Pointer(&buf[26:28][0])) = msg.r0.Type
copy(buf[28:32], msg.a0[:])
*(*uint16)(unsafe.Pointer(&buf[32:34][0])) = msg.r1.Len
*(*uint16)(unsafe.Pointer(&buf[34:36][0])) = msg.r1.Type
copy(buf[36:40], msg.a1[:])
return buf[:]
}
// newlinkLo represents a RTM_NEWLINK message.
type newlinkLo struct {
header NlMsghdr
data IfInfomsg
}
// sizeofNewlinkLo is the expected size of newlinkLo.
const sizeofNewlinkLo = NLMSG_HDRLEN + SizeofIfInfomsg
// newlinkLo returns the address of a populated newlinkLo.
func (s *rtnetlink) newlinkLo(lo int) *newlinkLo {
return &newlinkLo{NlMsghdr{
Len: sizeofNewlinkLo,
Type: RTM_NEWLINK,
Flags: NLM_F_REQUEST | NLM_F_ACK,
Seq: s.seq,
Pid: s.pid,
}, IfInfomsg{
Family: AF_UNSPEC,
Index: int32(lo),
Flags: IFF_UP,
Change: IFF_UP,
}}
}
func (msg *newlinkLo) toWireFormat() []byte {
var buf [sizeofNewlinkLo]byte
*(*uint32)(unsafe.Pointer(&buf[0:4][0])) = msg.header.Len
*(*uint16)(unsafe.Pointer(&buf[4:6][0])) = msg.header.Type
*(*uint16)(unsafe.Pointer(&buf[6:8][0])) = msg.header.Flags
*(*uint32)(unsafe.Pointer(&buf[8:12][0])) = msg.header.Seq
*(*uint32)(unsafe.Pointer(&buf[12:16][0])) = msg.header.Pid
buf[16] = msg.data.Family
*(*uint16)(unsafe.Pointer(&buf[18:20][0])) = msg.data.Type
*(*int32)(unsafe.Pointer(&buf[20:24][0])) = msg.data.Index
*(*uint32)(unsafe.Pointer(&buf[24:28][0])) = msg.data.Flags
*(*uint32)(unsafe.Pointer(&buf[28:32][0])) = msg.data.Change
return buf[:]
}
// mustLoopback creates the loopback address and brings the lo interface up.
// mustLoopback calls a fatal method of the underlying [log.Logger] of m with a
// user-facing error message if RTNETLINK behaves unexpectedly.
func mustLoopback(msg message.Msg) {
log := msg.GetLogger()
var lo int
if ifi, err := net.InterfaceByName("lo"); err != nil {
log.Fatalln(err)
} else {
lo = ifi.Index
}
var s rtnetlink
if err := s.open(); err != nil {
log.Fatalln(err)
}
defer func() {
if err := s.close(); err != nil {
msg.Verbosef("cannot close netlink: %v", err)
}
}()
s.mustRoundtrip(msg, s.newaddrLo(lo).toWireFormat())
s.mustRoundtrip(msg, s.newlinkLo(lo).toWireFormat())
}

View File

@@ -1,72 +0,0 @@
package container
import (
"testing"
"unsafe"
)
func TestSizeof(t *testing.T) {
if got := unsafe.Sizeof(newaddrLo{}); got != sizeofNewaddrLo {
t.Fatalf("newaddrLo: sizeof = %#x, want %#x", got, sizeofNewaddrLo)
}
if got := unsafe.Sizeof(newlinkLo{}); got != sizeofNewlinkLo {
t.Fatalf("newlinkLo: sizeof = %#x, want %#x", got, sizeofNewlinkLo)
}
}
func TestRtnetlinkMessage(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
msg interface{ toWireFormat() []byte }
want []byte
}{
{"newaddrLo", (&rtnetlink{pid: 1, seq: 0}).newaddrLo(1), []byte{
/* Len */ 0x28, 0, 0, 0,
/* Type */ 0x14, 0,
/* Flags */ 5, 6,
/* Seq */ 0, 0, 0, 0,
/* Pid */ 1, 0, 0, 0,
/* Family */ 2,
/* Prefixlen */ 8,
/* Flags */ 0x80,
/* Scope */ 0xfe,
/* Index */ 1, 0, 0, 0,
/* Len */ 8, 0,
/* Type */ 2, 0,
/* in_addr */ 127, 0, 0, 1,
/* Len */ 8, 0,
/* Type */ 1, 0,
/* in_addr */ 127, 0, 0, 1,
}},
{"newlinkLo", (&rtnetlink{pid: 1, seq: 1}).newlinkLo(1), []byte{
/* Len */ 0x20, 0, 0, 0,
/* Type */ 0x10, 0,
/* Flags */ 5, 0,
/* Seq */ 1, 0, 0, 0,
/* Pid */ 1, 0, 0, 0,
/* Family */ 0,
/* pad */ 0,
/* Type */ 0, 0,
/* Index */ 1, 0, 0, 0,
/* Flags */ 1, 0, 0, 0,
/* Change */ 1, 0, 0, 0,
}},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := tc.msg.toWireFormat(); string(got) != string(tc.want) {
t.Fatalf("toWireFormat: %#v, want %#v", got, tc.want)
}
})
}
}

View File

@@ -82,7 +82,7 @@ type Config struct {
//
// Do not set this to true, it is insecure under any configuration.
//
// [the /.flatpak-info hack]: https://git.gensokyo.uk/security/hakurei/issues/21
// [the /.flatpak-info hack]: https://git.gensokyo.uk/rosa/hakurei/issues/21
DirectPipeWire bool `json:"direct_pipewire,omitempty"`
// Direct access to PulseAudio socket, no attempt is made to establish

186
internal/netlink/netlink.go Normal file
View File

@@ -0,0 +1,186 @@
// Package netlink is a partial implementation of the netlink protocol.
package netlink
import (
"fmt"
"os"
"sync"
"syscall"
"unsafe"
)
// AF_NETLINK socket is never shared
var (
nlPid uint32
nlPidOnce sync.Once
)
// getpid returns a cached pid value.
func getpid() uint32 {
nlPidOnce.Do(func() { nlPid = uint32(os.Getpid()) })
return nlPid
}
// A conn represents resources associated to a netlink socket.
type conn struct {
// AF_NETLINK socket.
fd int
// Kernel module or netlink group to communicate with.
family int
// Message sequence number.
seq uint32
// For pending outgoing message.
typ, flags uint16
// Outgoing position in buf.
pos int
// A page holding incoming and outgoing messages.
buf []byte
}
// dial returns the address of a newly connected conn of specified family.
func dial(family int) (*conn, error) {
var c conn
if fd, err := syscall.Socket(
syscall.AF_NETLINK,
syscall.SOCK_RAW|syscall.SOCK_CLOEXEC,
family,
); err != nil {
return nil, os.NewSyscallError("socket", err)
} else if err = syscall.Bind(fd, &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
Pid: getpid(),
}); err != nil {
_ = syscall.Close(fd)
return nil, os.NewSyscallError("bind", err)
} else {
c.fd, c.family = fd, family
}
c.pos = syscall.NLMSG_HDRLEN
c.buf = make([]byte, os.Getpagesize())
return &c, nil
}
// Close closes the underlying socket.
func (c *conn) Close() error {
if c.buf == nil {
return syscall.EINVAL
}
c.buf = nil
return syscall.Close(c.fd)
}
// Msg is type constraint for types sent over the wire via netlink.
//
// No pointer types or compound types containing pointers may appear here.
type Msg interface {
syscall.NlMsghdr | syscall.NlMsgerr |
syscall.IfAddrmsg | RtAttrMsg[InAddr] |
syscall.IfInfomsg
}
// As returns data as the specified netlink message type.
func As[M Msg](data []byte) *M {
var v M
if unsafe.Sizeof(v) != uintptr(len(data)) {
return nil
}
return (*M)(unsafe.Pointer(unsafe.SliceData(data)))
}
// add queues a value to be sent by conn.
func add[M Msg](c *conn, p *M) bool {
pos := c.pos
c.pos += int(unsafe.Sizeof(*p))
if c.pos > len(c.buf) {
c.pos = pos
return false
}
*(*M)(unsafe.Pointer(&c.buf[pos])) = *p
return true
}
// InconsistentError describes a reply from the kernel that is not consistent
// with the internal state tracked by this package.
type InconsistentError struct {
// Offending header.
syscall.NlMsghdr
// Expected message sequence.
Seq uint32
// Expected pid.
Pid uint32
}
func (*InconsistentError) Unwrap() error { return os.ErrInvalid }
func (e *InconsistentError) Error() string {
s := "netlink socket has inconsistent state"
switch {
case e.Seq != e.NlMsghdr.Seq:
s += fmt.Sprintf(": seq %d != %d", e.Seq, e.NlMsghdr.Seq)
case e.Pid != e.NlMsghdr.Pid:
s += fmt.Sprintf(": pid %d != %d", e.Pid, e.NlMsghdr.Pid)
}
return s
}
// pending returns the valid slice of buf and initialises pos.
func (c *conn) pending() []byte {
buf := c.buf[:c.pos]
c.pos = syscall.NLMSG_HDRLEN
*(*syscall.NlMsghdr)(unsafe.Pointer(unsafe.SliceData(buf))) = syscall.NlMsghdr{
Len: uint32(len(buf)),
Type: c.typ,
Flags: c.flags,
Seq: c.seq,
Pid: getpid(),
}
return buf
}
// Complete indicates the completion of a roundtrip.
type Complete struct{}
// Error returns a hardcoded string that should never be displayed to the user.
func (Complete) Error() string { return "returning from roundtrip" }
// Roundtrip sends the pending message and handles the reply.
func (c *conn) Roundtrip(f func(msg *syscall.NetlinkMessage) error) error {
if c.buf == nil {
return syscall.EINVAL
}
defer func() { c.seq++ }()
if err := syscall.Sendto(c.fd, c.pending(), 0, &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
}); err != nil {
return os.NewSyscallError("sendto", err)
}
for {
buf := c.buf
if n, _, err := syscall.Recvfrom(c.fd, buf, 0); err != nil {
return os.NewSyscallError("recvfrom", err)
} else if n < syscall.NLMSG_HDRLEN {
return syscall.EBADE
} else {
buf = buf[:n]
}
msgs, err := syscall.ParseNetlinkMessage(buf)
if err != nil {
return err
}
for _, msg := range msgs {
if msg.Header.Seq != c.seq || msg.Header.Pid != getpid() {
return &InconsistentError{msg.Header, c.seq, getpid()}
}
if err = f(&msg); err != nil {
if err == (Complete{}) {
return nil
}
return err
}
}
}
}

View File

@@ -0,0 +1,36 @@
package netlink
import (
"os"
"syscall"
"testing"
)
func init() { nlPidOnce.Do(func() {}); nlPid = 1 }
type payloadTestCase struct {
name string
f func(c *conn)
want []byte
}
// checkPayload runs multiple payloadTestCase against a stub conn and checks
// the outgoing message written to its buffer page.
func checkPayload(t *testing.T, testCases []payloadTestCase) {
t.Helper()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
c := conn{
pos: syscall.NLMSG_HDRLEN,
buf: make([]byte, os.Getpagesize()),
}
tc.f(&c)
if got := c.pending(); string(got) != string(tc.want) {
t.Errorf("pending: %#v, want %#v", got, tc.want)
}
})
}
}

132
internal/netlink/rtnl.go Normal file
View File

@@ -0,0 +1,132 @@
package netlink
import (
"syscall"
"unsafe"
)
// RouteConn represents a NETLINK_ROUTE socket.
type RouteConn struct{ *conn }
// DialRoute returns the address of a newly connected [RouteConn].
func DialRoute() (*RouteConn, error) {
c, err := dial(syscall.NETLINK_ROUTE)
if err != nil {
return nil, err
}
return &RouteConn{c}, nil
}
// rtnlConsume consumes a message from rtnetlink.
func rtnlConsume(msg *syscall.NetlinkMessage) error {
switch msg.Header.Type {
case syscall.NLMSG_DONE:
return Complete{}
case syscall.NLMSG_ERROR:
if e := As[syscall.NlMsgerr](msg.Data); e != nil {
if e.Error == 0 {
return Complete{}
}
return syscall.Errno(-e.Error)
}
return syscall.EBADE
default:
return nil
}
}
// InAddr is equivalent to struct in_addr.
type InAddr [4]byte
// RtAttrMsg holds syscall.RtAttr alongside its payload.
type RtAttrMsg[D any] struct {
syscall.RtAttr
Data D
}
// populate populates the Len field of the embedded syscall.RtAttr.
func (attr *RtAttrMsg[M]) populate() {
attr.Len = syscall.SizeofRtAttr + uint16(unsafe.Sizeof(attr.Data))
}
// writeIfAddrmsg writes an ifaddrmsg structure to conn.
func (c *RouteConn) writeIfAddrmsg(
typ, flags uint16,
msg *syscall.IfAddrmsg,
attrs ...RtAttrMsg[InAddr],
) bool {
c.typ, c.flags = typ, syscall.NLM_F_REQUEST|syscall.NLM_F_ACK|flags
if !add(c.conn, msg) {
return false
}
for _, attr := range attrs {
attr.populate()
if !add(c.conn, &attr) {
return false
}
}
return true
}
// SendIfAddrmsg sends an ifaddrmsg structure to rtnetlink.
func (c *RouteConn) SendIfAddrmsg(
typ, flags uint16,
msg *syscall.IfAddrmsg,
attrs ...RtAttrMsg[InAddr],
) error {
if !c.writeIfAddrmsg(typ, flags, msg, attrs...) {
return syscall.ENOMEM
}
return c.Roundtrip(rtnlConsume)
}
// writeNewaddrLo writes a RTM_NEWADDR message for the loopback address.
func (c *RouteConn) writeNewaddrLo(lo uint32) bool {
return c.writeIfAddrmsg(
syscall.RTM_NEWADDR,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
&syscall.IfAddrmsg{
Family: syscall.AF_INET,
Prefixlen: 8,
Flags: syscall.IFA_F_PERMANENT,
Scope: syscall.RT_SCOPE_HOST,
Index: lo,
},
RtAttrMsg[InAddr]{syscall.RtAttr{
Type: syscall.IFA_LOCAL,
}, InAddr{127, 0, 0, 1}},
RtAttrMsg[InAddr]{syscall.RtAttr{
Type: syscall.IFA_ADDRESS,
}, InAddr{127, 0, 0, 1}},
)
}
// SendNewaddrLo sends a RTM_NEWADDR message for the loopback address to the kernel.
func (c *RouteConn) SendNewaddrLo(lo uint32) error {
if !c.writeNewaddrLo(lo) {
return syscall.ENOMEM
}
return c.Roundtrip(rtnlConsume)
}
// writeIfInfomsg writes an ifinfomsg structure to conn.
func (c *RouteConn) writeIfInfomsg(
typ, flags uint16,
msg *syscall.IfInfomsg,
) bool {
c.typ, c.flags = typ, syscall.NLM_F_REQUEST|syscall.NLM_F_ACK|flags
return add(c.conn, msg)
}
// SendIfInfomsg sends an ifinfomsg structure to rtnetlink.
func (c *RouteConn) SendIfInfomsg(
typ, flags uint16,
msg *syscall.IfInfomsg,
) error {
if !c.writeIfInfomsg(typ, flags, msg) {
return syscall.ENOMEM
}
return c.Roundtrip(rtnlConsume)
}

View File

@@ -0,0 +1,62 @@
package netlink
import (
"syscall"
"testing"
)
func TestPayloadRTNETLINK(t *testing.T) {
t.Parallel()
checkPayload(t, []payloadTestCase{
{"RTM_NEWADDR lo", func(c *conn) {
(&RouteConn{c}).writeNewaddrLo(1)
}, []byte{
/* Len */ 0x28, 0, 0, 0,
/* Type */ 0x14, 0,
/* Flags */ 5, 6,
/* Seq */ 0, 0, 0, 0,
/* Pid */ 1, 0, 0, 0,
/* Family */ 2,
/* Prefixlen */ 8,
/* Flags */ 0x80,
/* Scope */ 0xfe,
/* Index */ 1, 0, 0, 0,
/* Len */ 8, 0,
/* Type */ 2, 0,
/* in_addr */ 127, 0, 0, 1,
/* Len */ 8, 0,
/* Type */ 1, 0,
/* in_addr */ 127, 0, 0, 1,
}},
{"RTM_NEWLINK", func(c *conn) {
c.seq++
(&RouteConn{c}).writeIfInfomsg(
syscall.RTM_NEWLINK, 0,
&syscall.IfInfomsg{
Family: syscall.AF_UNSPEC,
Index: 1,
Flags: syscall.IFF_UP,
Change: syscall.IFF_UP,
},
)
}, []byte{
/* Len */ 0x20, 0, 0, 0,
/* Type */ 0x10, 0,
/* Flags */ 5, 0,
/* Seq */ 1, 0, 0, 0,
/* Pid */ 1, 0, 0, 0,
/* Family */ 0,
/* pad */ 0,
/* Type */ 0, 0,
/* Index */ 1, 0, 0, 0,
/* Flags */ 1, 0, 0, 0,
/* Change */ 1, 0, 0, 0,
}},
})
}

View File

@@ -20,8 +20,10 @@ const (
LLVMRuntimes
LLVMClang
// EarlyInit is the Rosa OS initramfs init program.
// EarlyInit is the Rosa OS init program.
EarlyInit
// ImageSystem is the Rosa OS /system image.
ImageSystem
// ImageInitramfs is the Rosa OS initramfs archive.
ImageInitramfs
@@ -110,21 +112,11 @@ const (
PkgConfig
Procps
Python
PythonCfgv
PythonDiscovery
PythonDistlib
PythonFilelock
PythonIdentify
PythonIniConfig
PythonNodeenv
PythonPackaging
PythonPlatformdirs
PythonPluggy
PythonPreCommit
PythonPyTest
PythonPyYAML
PythonPygments
PythonVirtualenv
QEMU
Rdfind
Rsync

View File

@@ -12,24 +12,11 @@ func (t Toolchain) newCurl() (pkg.Artifact, string) {
mustDecode(checksum),
pkg.TarBzip2,
), &PackageAttr{
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>
`},
},
// remove broken test
Writable: true,
ScriptEarly: `
chmod +w tests/data && rm tests/data/test459
`,
}, &MakeHelper{
Configure: [][2]string{
{"with-openssl"},

View File

@@ -4,13 +4,13 @@ package rosa
import "hakurei.app/internal/pkg"
const hakureiVersion = "0.3.6"
const hakureiVersion = "0.3.7"
// hakureiSource is the source code of a hakurei release.
var hakureiSource = pkg.NewHTTPGetTar(
nil, "https://git.gensokyo.uk/security/hakurei/archive/"+
nil, "https://git.gensokyo.uk/rosa/hakurei/archive/"+
"v"+hakureiVersion+".tar.gz",
mustDecode("Yul9J2yV0x453lQP9KUnG_wEJo_DbKMNM7xHJGt4rITCSeX9VRK2J4kzAxcv_0-b"),
mustDecode("Xh_sdITOATEAQN5_UuaOyrWsgboxorqRO9bml3dGm8GAxF8NFpB7MqhSZgjJxAl2"),
pkg.TarGzip,
)

View File

@@ -1,6 +1,9 @@
package rosa
import "hakurei.app/internal/pkg"
import (
"hakurei.app/container/fhs"
"hakurei.app/internal/pkg"
)
func init() {
artifactsM[EarlyInit] = Metadata{
@@ -24,12 +27,36 @@ 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) {
return t.New("initramfs", TNoToolchain, []pkg.Artifact{
t.Load(Zstd),
t.Load(EarlyInit),
t.Load(GenInitCPIO),
}, nil, nil, `
return t.New("initramfs", TNoToolchain, t.AppendPresets(nil,
Zstd,
EarlyInit,
GenInitCPIO,
), nil, nil, `
gen_init_cpio -t 4294967295 -c /usr/src/initramfs | zstd > /work/initramfs.zst
`, pkg.Path(AbsUsrSrc.Append("initramfs"), false, pkg.NewFile("initramfs", []byte(`
dir /dev 0755 0 0

View File

@@ -2,12 +2,12 @@ package rosa
import "hakurei.app/internal/pkg"
const kernelVersion = "6.12.76"
const kernelVersion = "6.12.77"
var kernelSource = pkg.NewHTTPGetTar(
nil, "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
"snapshot/linux-"+kernelVersion+".tar.gz",
mustDecode("h0UATNznQbzplvthAqNLjVF-DJQHzGyhiy4za-9Ig9tOIpnoH9mWHbEjASV6lOl2"),
mustDecode("_MyFL0MqqNwAJx4fP8L9FkUayXIqEJto5trAPr_9UJvaT5TK1tvlU8leS82Hw2uw"),
pkg.TarGzip,
)

View File

@@ -2,15 +2,15 @@
# Automatically generated file; DO NOT EDIT.
# Linux/x86 6.12.76 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="clang version 22.1.0"
CONFIG_CC_VERSION_TEXT="clang version 22.1.1"
CONFIG_GCC_VERSION=0
CONFIG_CC_IS_CLANG=y
CONFIG_CLANG_VERSION=220100
CONFIG_CLANG_VERSION=220101
CONFIG_AS_IS_LLVM=y
CONFIG_AS_VERSION=220100
CONFIG_AS_VERSION=220101
CONFIG_LD_VERSION=0
CONFIG_LD_IS_LLD=y
CONFIG_LLD_VERSION=220100
CONFIG_LLD_VERSION=220101
CONFIG_RUSTC_VERSION=0
CONFIG_RUSTC_LLVM_VERSION=0
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
@@ -2402,7 +2402,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Firmware loader
#
CONFIG_FW_LOADER=m
CONFIG_FW_LOADER=y
CONFIG_FW_LOADER_DEBUG=y
CONFIG_FW_LOADER_PAGED_BUF=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_RAWCMD is not set
CONFIG_CDROM=m
CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
CONFIG_BLK_DEV_PCIESSD_MTIP32XX=y
CONFIG_ZRAM=m
# CONFIG_ZRAM_BACKEND_LZ4 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_WCACHE is not set
CONFIG_ATA_OVER_ETH=m
CONFIG_XEN_BLKDEV_FRONTEND=m
CONFIG_XEN_BLKDEV_BACKEND=m
CONFIG_VIRTIO_BLK=m
CONFIG_XEN_BLKDEV_FRONTEND=y
# CONFIG_XEN_BLKDEV_BACKEND is not set
CONFIG_VIRTIO_BLK=y
CONFIG_BLK_DEV_RBD=m
CONFIG_BLK_DEV_UBLK=m
CONFIG_BLKDEV_UBLK_LEGACY_OPCODES=y
@@ -2788,13 +2788,12 @@ CONFIG_BLK_DEV_RNBD_SERVER=m
#
# NVME Support
#
CONFIG_NVME_KEYRING=m
CONFIG_NVME_AUTH=m
CONFIG_NVME_CORE=m
CONFIG_BLK_DEV_NVME=m
CONFIG_NVME_KEYRING=y
CONFIG_NVME_AUTH=y
CONFIG_NVME_CORE=y
CONFIG_BLK_DEV_NVME=y
CONFIG_NVME_MULTIPATH=y
# CONFIG_NVME_VERBOSE_ERRORS is not set
CONFIG_NVME_HWMON=y
CONFIG_NVME_FABRICS=m
CONFIG_NVME_RDMA=m
CONFIG_NVME_FC=m
@@ -2911,10 +2910,10 @@ CONFIG_KEBA_CP500=m
#
# SCSI device support
#
CONFIG_SCSI_MOD=m
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=m
CONFIG_SCSI_COMMON=m
CONFIG_SCSI=m
CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -2922,7 +2921,7 @@ CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=m
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=m
CONFIG_CHR_DEV_SG=m
@@ -3042,7 +3041,7 @@ CONFIG_SCSI_DEBUG=m
CONFIG_SCSI_PMCRAID=m
CONFIG_SCSI_PM8001=m
CONFIG_SCSI_BFA_FC=m
CONFIG_SCSI_VIRTIO=m
CONFIG_SCSI_VIRTIO=y
CONFIG_SCSI_CHELSIO_FCOE=m
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
CONFIG_PCMCIA_AHA152X=m
@@ -3052,7 +3051,7 @@ CONFIG_PCMCIA_SYM53C500=m
# CONFIG_SCSI_DH is not set
# end of SCSI device support
CONFIG_ATA=m
CONFIG_ATA=y
CONFIG_SATA_HOST=y
CONFIG_PATA_TIMINGS=y
CONFIG_ATA_VERBOSE_ERROR=y
@@ -3064,39 +3063,39 @@ CONFIG_SATA_PMP=y
#
# Controllers with non-SFF native interface
#
CONFIG_SATA_AHCI=m
CONFIG_SATA_AHCI=y
CONFIG_SATA_MOBILE_LPM_POLICY=3
CONFIG_SATA_AHCI_PLATFORM=m
CONFIG_AHCI_DWC=m
CONFIG_AHCI_CEVA=m
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_DWC=y
CONFIG_AHCI_CEVA=y
CONFIG_SATA_INIC162X=m
CONFIG_SATA_ACARD_AHCI=m
CONFIG_SATA_SIL24=m
CONFIG_SATA_ACARD_AHCI=y
CONFIG_SATA_SIL24=y
CONFIG_ATA_SFF=y
#
# SFF controllers with custom DMA interface
#
CONFIG_PDC_ADMA=m
CONFIG_SATA_QSTOR=m
CONFIG_PDC_ADMA=y
CONFIG_SATA_QSTOR=y
CONFIG_SATA_SX4=m
CONFIG_ATA_BMDMA=y
#
# SATA SFF controllers with BMDMA
#
CONFIG_ATA_PIIX=m
CONFIG_SATA_DWC=m
CONFIG_ATA_PIIX=y
CONFIG_SATA_DWC=y
# CONFIG_SATA_DWC_OLD_DMA is not set
CONFIG_SATA_MV=m
CONFIG_SATA_NV=m
CONFIG_SATA_PROMISE=m
CONFIG_SATA_SIL=m
CONFIG_SATA_SIS=m
CONFIG_SATA_SVW=m
CONFIG_SATA_ULI=m
CONFIG_SATA_VIA=m
CONFIG_SATA_VITESSE=m
CONFIG_SATA_MV=y
CONFIG_SATA_NV=y
CONFIG_SATA_PROMISE=y
CONFIG_SATA_SIL=y
CONFIG_SATA_SIS=y
CONFIG_SATA_SVW=y
CONFIG_SATA_ULI=y
CONFIG_SATA_VIA=y
CONFIG_SATA_VITESSE=y
#
# PATA SFF controllers with BMDMA
@@ -3130,7 +3129,7 @@ CONFIG_PATA_RDC=m
CONFIG_PATA_SCH=m
CONFIG_PATA_SERVERWORKS=m
CONFIG_PATA_SIL680=m
CONFIG_PATA_SIS=m
CONFIG_PATA_SIS=y
CONFIG_PATA_TOSHIBA=m
CONFIG_PATA_TRIFLEX=m
CONFIG_PATA_VIA=m
@@ -3172,8 +3171,8 @@ CONFIG_PATA_PARPORT_ON26=m
#
# Generic fallback / legacy drivers
#
CONFIG_PATA_ACPI=m
CONFIG_ATA_GENERIC=m
CONFIG_PATA_ACPI=y
CONFIG_ATA_GENERIC=y
CONFIG_PATA_LEGACY=m
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
@@ -9621,11 +9620,11 @@ CONFIG_EFI_SECRET=m
CONFIG_SEV_GUEST=m
CONFIG_TDX_GUEST_DRIVER=m
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=m
CONFIG_VIRTIO_PCI_LIB=m
CONFIG_VIRTIO_PCI_LIB_LEGACY=m
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=m
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_ADMIN_LEGACY=y
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_VDPA=m

View File

@@ -2,15 +2,15 @@
# Automatically generated file; DO NOT EDIT.
# Linux/arm64 6.12.76 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="clang version 22.1.0"
CONFIG_CC_VERSION_TEXT="clang version 22.1.1"
CONFIG_GCC_VERSION=0
CONFIG_CC_IS_CLANG=y
CONFIG_CLANG_VERSION=220100
CONFIG_CLANG_VERSION=220101
CONFIG_AS_IS_LLVM=y
CONFIG_AS_VERSION=220100
CONFIG_AS_VERSION=220101
CONFIG_LD_VERSION=0
CONFIG_LD_IS_LLD=y
CONFIG_LLD_VERSION=220100
CONFIG_LLD_VERSION=220101
CONFIG_RUSTC_VERSION=0
CONFIG_RUSTC_LLVM_VERSION=0
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
@@ -2384,7 +2384,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Firmware loader
#
CONFIG_FW_LOADER=m
CONFIG_FW_LOADER=y
CONFIG_FW_LOADER_DEBUG=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_FW_LOADER_SYSFS=y
@@ -2849,8 +2849,8 @@ CONFIG_CDROM_PKTCDVD=m
CONFIG_CDROM_PKTCDVD_BUFFERS=8
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
CONFIG_ATA_OVER_ETH=m
CONFIG_XEN_BLKDEV_FRONTEND=m
CONFIG_XEN_BLKDEV_BACKEND=m
CONFIG_XEN_BLKDEV_FRONTEND=y
# CONFIG_XEN_BLKDEV_BACKEND is not set
CONFIG_VIRTIO_BLK=m
CONFIG_BLK_DEV_RBD=m
CONFIG_BLK_DEV_UBLK=m
@@ -2862,13 +2862,12 @@ CONFIG_BLK_DEV_RNBD_SERVER=m
#
# NVME Support
#
CONFIG_NVME_KEYRING=m
CONFIG_NVME_AUTH=m
CONFIG_NVME_CORE=m
CONFIG_BLK_DEV_NVME=m
CONFIG_NVME_KEYRING=y
CONFIG_NVME_AUTH=y
CONFIG_NVME_CORE=y
CONFIG_BLK_DEV_NVME=y
CONFIG_NVME_MULTIPATH=y
# CONFIG_NVME_VERBOSE_ERRORS is not set
CONFIG_NVME_HWMON=y
CONFIG_NVME_FABRICS=m
CONFIG_NVME_RDMA=m
CONFIG_NVME_FC=m
@@ -2977,10 +2976,10 @@ CONFIG_KEBA_CP500=m
#
# SCSI device support
#
CONFIG_SCSI_MOD=m
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=m
CONFIG_SCSI_COMMON=m
CONFIG_SCSI=m
CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -2988,7 +2987,7 @@ CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=m
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=m
CONFIG_CHR_DEV_SG=m
@@ -3108,7 +3107,7 @@ CONFIG_SCSI_DEBUG=m
CONFIG_SCSI_PMCRAID=m
CONFIG_SCSI_PM8001=m
CONFIG_SCSI_BFA_FC=m
CONFIG_SCSI_VIRTIO=m
CONFIG_SCSI_VIRTIO=y
CONFIG_SCSI_CHELSIO_FCOE=m
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
CONFIG_PCMCIA_AHA152X=m
@@ -3118,7 +3117,7 @@ CONFIG_PCMCIA_SYM53C500=m
# CONFIG_SCSI_DH is not set
# end of SCSI device support
CONFIG_ATA=m
CONFIG_ATA=y
CONFIG_SATA_HOST=y
CONFIG_PATA_TIMINGS=y
CONFIG_ATA_VERBOSE_ERROR=y
@@ -3130,23 +3129,23 @@ CONFIG_SATA_PMP=y
#
# Controllers with non-SFF native interface
#
CONFIG_SATA_AHCI=m
CONFIG_SATA_AHCI=y
CONFIG_SATA_MOBILE_LPM_POLICY=3
CONFIG_SATA_AHCI_PLATFORM=m
CONFIG_AHCI_BRCM=m
CONFIG_AHCI_DWC=m
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_BRCM=y
CONFIG_AHCI_DWC=y
CONFIG_AHCI_IMX=m
CONFIG_AHCI_CEVA=m
CONFIG_AHCI_MTK=m
CONFIG_AHCI_MVEBU=m
CONFIG_AHCI_SUNXI=m
CONFIG_AHCI_TEGRA=m
CONFIG_AHCI_CEVA=y
CONFIG_AHCI_MTK=y
CONFIG_AHCI_MVEBU=y
CONFIG_AHCI_SUNXI=y
CONFIG_AHCI_TEGRA=y
CONFIG_AHCI_XGENE=m
CONFIG_AHCI_QORIQ=m
CONFIG_SATA_AHCI_SEATTLE=m
CONFIG_AHCI_QORIQ=y
CONFIG_SATA_AHCI_SEATTLE=y
CONFIG_SATA_INIC162X=m
CONFIG_SATA_ACARD_AHCI=m
CONFIG_SATA_SIL24=m
CONFIG_SATA_ACARD_AHCI=y
CONFIG_SATA_SIL24=y
CONFIG_ATA_SFF=y
#
@@ -3160,19 +3159,19 @@ CONFIG_ATA_BMDMA=y
#
# SATA SFF controllers with BMDMA
#
CONFIG_ATA_PIIX=m
CONFIG_SATA_DWC=m
CONFIG_ATA_PIIX=y
CONFIG_SATA_DWC=y
# CONFIG_SATA_DWC_OLD_DMA is not set
CONFIG_SATA_MV=m
CONFIG_SATA_NV=m
CONFIG_SATA_PROMISE=m
CONFIG_SATA_RCAR=m
CONFIG_SATA_SIL=m
CONFIG_SATA_SIS=m
CONFIG_SATA_SVW=m
CONFIG_SATA_ULI=m
CONFIG_SATA_VIA=m
CONFIG_SATA_VITESSE=m
CONFIG_SATA_MV=y
CONFIG_SATA_NV=y
CONFIG_SATA_PROMISE=y
CONFIG_SATA_RCAR=y
CONFIG_SATA_SIL=y
CONFIG_SATA_SIS=y
CONFIG_SATA_SVW=y
CONFIG_SATA_ULI=y
CONFIG_SATA_VIA=y
CONFIG_SATA_VITESSE=y
#
# PATA SFF controllers with BMDMA
@@ -3207,7 +3206,7 @@ CONFIG_PATA_RDC=m
CONFIG_PATA_SCH=m
CONFIG_PATA_SERVERWORKS=m
CONFIG_PATA_SIL680=m
CONFIG_PATA_SIS=m
CONFIG_PATA_SIS=y
CONFIG_PATA_TOSHIBA=m
CONFIG_PATA_TRIFLEX=m
CONFIG_PATA_VIA=m
@@ -3249,8 +3248,8 @@ CONFIG_PATA_PARPORT_ON26=m
#
# Generic fallback / legacy drivers
#
CONFIG_PATA_ACPI=m
CONFIG_ATA_GENERIC=m
CONFIG_PATA_ACPI=y
CONFIG_ATA_GENERIC=y
CONFIG_PATA_LEGACY=m
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
@@ -10436,11 +10435,11 @@ CONFIG_VMGENID=m
CONFIG_NITRO_ENCLAVES=m
CONFIG_ARM_PKVM_GUEST=y
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=m
CONFIG_VIRTIO_PCI_LIB=m
CONFIG_VIRTIO_PCI_LIB_LEGACY=m
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=m
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_VDPA=m
CONFIG_VIRTIO_PMEM=m

View File

@@ -73,14 +73,8 @@ func llvmFlagName(flag int) string {
}
}
const (
llvmVersionMajor = "22"
llvmVersion = llvmVersionMajor + ".1.1"
)
// newLLVMVariant returns a [pkg.Artifact] containing a LLVM variant.
func (t Toolchain) newLLVMVariant(variant string, attr *llvmAttr) pkg.Artifact {
const checksum = "bQvV6D8AZvQykg7-uQb_saTbVavnSo1ykNJ3g57F5iE-evU3HuOYtcRnVIXTK76e"
if attr == nil {
panic("LLVM attr must be non-nil")
@@ -169,7 +163,7 @@ ln -s ld.lld /work/system/bin/ld
return t.NewPackage("llvm", llvmVersion, pkg.NewHTTPGetTar(
nil, "https://github.com/llvm/llvm-project/archive/refs/tags/"+
"llvmorg-"+llvmVersion+".tar.gz",
mustDecode(checksum),
mustDecode(llvmChecksum),
pkg.TarGzip,
), &PackageAttr{
Patches: attr.patches,
@@ -316,7 +310,7 @@ ln -s clang++ /work/system/bin/c++
ninja check-all
`,
patches: [][2]string{
patches: slices.Concat([][2]string{
{"add-rosa-vendor", `diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 9c83abeeb3b1..5acfe5836a23 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
@@ -488,7 +482,7 @@ index 64324a3f8b01..15ce70b68217 100644
"/System/Library/Frameworks"};
`},
},
}, clangPatches),
})
return

View File

@@ -0,0 +1,4 @@
package rosa
// clangPatches are patches applied to the LLVM source tree for building clang.
var clangPatches [][2]string

View File

@@ -0,0 +1,12 @@
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"
)

View File

@@ -0,0 +1,11 @@
//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"
)

View File

@@ -9,8 +9,8 @@ import (
func (t Toolchain) newMeson() (pkg.Artifact, string) {
const (
version = "1.10.1"
checksum = "w895BXF_icncnXatT_OLCFe2PYEtg4KrKooMgUYdN-nQVvbFX3PvYWHGEpogsHtd"
version = "1.10.2"
checksum = "18VmKUVKuXCwtawkYCeYHseC3cKpi86OhnIPaV878wjY0rkXH8XnQwUyymnxFgcl"
)
return t.New("meson-"+version, 0, []pkg.Artifact{
t.Load(Zlib),

View File

@@ -195,103 +195,4 @@ func init() {
PythonPluggy,
PythonPygments,
)
artifactsM[PythonCfgv] = newViaPip(
"cfgv",
"validate configuration and produce human readable error messages",
"3.5.0", "py2.py3", "none", "any",
"yFKTyVRlmnLKAxvvge15kAd_GOP1Xh3fZ0NFImO5pBdD5e0zj3GRmA6Q1HdtLTYO",
"https://files.pythonhosted.org/packages/"+
"db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/",
)
artifactsM[PythonIdentify] = newViaPip(
"identify",
"file identification library for Python",
"2.6.17", "py2.py3", "none", "any",
"9RxK3igO-Pxxof5AuCAGiF_L1SWi4SpuSF1fWNXCzE2D4oTRSob-9VpFMLlybrSv",
"https://files.pythonhosted.org/packages/"+
"40/66/71c1227dff78aaeb942fed29dd5651f2aec166cc7c9aeea3e8b26a539b7d/",
)
artifactsM[PythonNodeenv] = newViaPip(
"nodeenv",
"a tool to create isolated node.js environments",
"1.10.0", "py2.py3", "none", "any",
"ihUb4-WQXYIhYOOKSsXlKIzjzQieOYl6ojro9H-0DFzGheaRTtuyZgsCmriq58sq",
"https://files.pythonhosted.org/packages/"+
"88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/",
)
artifactsM[PythonPyYAML] = newViaPip(
"pyyaml",
"a complete YAML 1.1 parser",
"6.0.3", "cp314", "cp314", "musllinux_1_2_x86_64",
"4_jhCFpUNtyrFp2HOMqUisR005u90MHId53eS7rkUbcGXkoaJ7JRsY21dREHEfGN",
"https://files.pythonhosted.org/packages/"+
"d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/",
)
artifactsM[PythonDistlib] = newViaPip(
"distlib",
"used as the basis for third-party packaging tools",
"0.4.0", "py2.py3", "none", "any",
"lGLLfYVhUhXOTw_84zULaH2K8n6pk1OOVXmJfGavev7N42msbtHoq-XY5D_xULI_",
"https://files.pythonhosted.org/packages/"+
"33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/",
)
artifactsM[PythonFilelock] = newViaPip(
"filelock",
"a platform-independent file locking library for Python",
"3.25.0", "py3", "none", "any",
"0gSQIYNUEjOs1JBxXjGwfLnwFPFINwqyU_Zqgj7fT_EGafv_HaD5h3Xv2Rq_qQ44",
"https://files.pythonhosted.org/packages/"+
"f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/",
)
artifactsM[PythonPlatformdirs] = newViaPip(
"platformdirs",
"a Python package for determining platform-specific directories",
"4.9.4", "py3", "none", "any",
"JGNpMCX2JMn-7c9bk3QzOSNDgJRR_5lH-jIqfy0zXMZppRCdLsTNbdp4V7QFwxOI",
"https://files.pythonhosted.org/packages/"+
"63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/",
)
artifactsM[PythonDiscovery] = newViaPip(
"python_discovery",
"looks for a python installation",
"1.1.1", "py3", "none", "any",
"Jk_qGMfZYm0fdNOSvMdVQZuQbJlqu3NWRm7T2fRtiBXmHLQyOdJE3ypI_it1OJR0",
"https://files.pythonhosted.org/packages/"+
"75/0f/2bf7e3b5a4a65f623cb820feb5793e243fad58ae561015ee15a6152f67a2/",
PythonFilelock,
PythonPlatformdirs,
)
artifactsM[PythonVirtualenv] = newViaPip(
"virtualenv",
"a tool for creating isolated virtual python environments",
"21.1.0", "py3", "none", "any",
"SLvdr3gJZ7GTS-kiRyq2RvJdrQ8SZYC1pglbViWCMLCuAIcbLNjVEUJZ4hDtKUxm",
"https://files.pythonhosted.org/packages/"+
"78/55/896b06bf93a49bec0f4ae2a6f1ed12bd05c8860744ac3a70eda041064e4d/",
PythonDistlib,
PythonDiscovery,
)
artifactsM[PythonPreCommit] = newViaPip(
"pre_commit",
"a framework for managing and maintaining multi-language pre-commit hooks",
"4.5.1", "py2.py3", "none", "any",
"9G2Hv5JpvXFZVfw4pv_KAsmHD6bvot9Z0YBDmW6JeJizqTA4xEQCKel-pCERqQFK",
"https://files.pythonhosted.org/packages/"+
"5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/",
PythonCfgv,
PythonIdentify,
PythonNodeenv,
PythonPyYAML,
PythonVirtualenv,
)
}

View File

@@ -17,6 +17,7 @@ func (t Toolchain) newTamaGo() (pkg.Artifact, string) {
), nil, []string{
"CC=cc",
"GOCACHE=/tmp/gocache",
"CGO_ENABLED=0",
}, `
mkdir /work/system # "${TMPDIR}"
cp -r /usr/src/tamago /work/system

View File

@@ -30,7 +30,7 @@
buildGo126Module rec {
pname = "hakurei";
version = "0.3.6";
version = "0.3.7";
srcFiltered = builtins.path {
name = "${pname}-src";