package main import ( "context" "os" "path/filepath" "runtime" "testing" "hakurei.app/check" "hakurei.app/container" "hakurei.app/internal/pkg" "hakurei.app/internal/rosa" "hakurei.app/message" ) // cache refers to an instance of [pkg.Cache] that might be open. type cache struct { ctx context.Context msg message.Msg // Should generally not be used directly. c *pkg.Cache cures, jobs int hostAbstract, idle bool verboseInit bool arch string base string } // open opens the underlying [pkg.Cache]. func (cache *cache) open() (err error) { if cache.c != nil { return os.ErrInvalid } var base *check.Absolute if cache.base, err = filepath.Abs(cache.base); err != nil { return } else if base, err = check.NewAbs(cache.base); err != nil { return } var flags int if cache.idle { flags |= pkg.CSchedIdle } if cache.hostAbstract { flags |= pkg.CHostAbstract } if !cache.verboseInit { flags |= pkg.CSuppressInit } done := make(chan struct{}) defer close(done) go func() { select { case <-cache.ctx.Done(): if testing.Testing() { return } os.Exit(2) case <-done: return } }() cache.msg.Verbosef("opening cache at %s", base) cache.c, err = pkg.Open( cache.ctx, cache.msg, flags, cache.cures, cache.jobs, base, ) if err != nil { return } done <- struct{}{} if cache.arch != "" && cache.arch != runtime.GOARCH { var ( name string offset byte magic string mask string ) switch cache.arch { case "riscv64": name = "riscv64" offset = 0 magic = "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00" mask = "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff" case "arm64": name = "aarch64" offset = 0 magic = "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00" mask = "\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff" default: cache.c.Close() err = pkg.UnsupportedArchError(cache.arch) return } var pathname *check.Absolute pathname, _, err = cache.c.Cure(rosa.Std.Load(rosa.QEMU)) if err != nil { cache.c.Close() return } pkg.RegisterArch(cache.arch, container.BinfmtEntry{ Offset: offset, Magic: magic, Mask: mask, Interpreter: pathname.Append( "system/bin", "qemu-"+name, ), }) rosa.DropCaches(cache.arch, rosa.Flags()) } return } // Close closes the underlying [pkg.Cache] if it is open. func (cache *cache) Close() { if cache.c != nil { cache.c.Close() } } // Do calls f on the underlying cache and returns its error value. func (cache *cache) Do(f func(cache *pkg.Cache) error) error { if cache.c == nil { if err := cache.open(); err != nil { return err } } return f(cache.c) }