//go:build linux package cgroup import ( "errors" "github.com/carlosframework/platform/internal/controlname" "golang.org/x/sys/unix" ) type ContainmentIdentity struct{ Device, Inode uint64 } func (p *Prepared) Identity() (ContainmentIdentity, error) { if p == nil || p.strictPreparedState == nil { return ContainmentIdentity{}, ErrStrictState } p.mu.Lock() defer p.mu.Unlock() if err := p.identityOK(); err != nil { return ContainmentIdentity{}, err } return ContainmentIdentity{Device: p.identity.device, Inode: p.identity.inode}, nil } // PrepareRoleChild pins a newly empty role group below the host parent. It // never reuses the parent's populated group and inherits its aggregate limits. func (p *Prepared) PrepareRoleChild(role string) (*Prepared, error) { return p.prepareRoleChild(role, nil) } // PrepareRoleChildWithIntent requires a new name and persists the caller's // intention under the pinned parent before mkdir. A failed preparation retains // that intention for stop recovery; it never authorizes execution by itself. func (p *Prepared) PrepareRoleChildWithIntent(role string, intent func(ContainmentIdentity) error) (*Prepared, error) { if intent == nil { return nil, ErrStrictRefused } return p.prepareRoleChild(role, intent) } func (p *Prepared) prepareRoleChild(role string, intent func(ContainmentIdentity) error) (out *Prepared, err error) { if p == nil || p.strictPreparedState == nil || !controlname.ValidLabel(role) { return nil, ErrStrictRefused } p.mu.Lock() defer p.mu.Unlock() if p.parent != nil || p.empty || p.draining.Load() { return nil, ErrStrictState } if err = p.identityOK(); err != nil { return nil, err } name := "role-" + role beforeMkdir := func() error { if intent != nil { var st unix.Stat_t if e := unix.Fstatat(int(p.dir.Fd()), name, &st, unix.AT_SYMLINK_NOFOLLOW); !errors.Is(e, unix.ENOENT) { return ErrStrictRefused } if e := intent(ContainmentIdentity{Device: p.identity.device, Inode: p.identity.inode}); e != nil { return e } } return nil } allowExisting := intent == nil child, err := pinChild(p, name, beforeMkdir, allowExisting) if err != nil { return nil, err } return child, nil }