package tentacle import ( "bytes" "encoding/json" "fmt" "io" "os" "path/filepath" "strings" "syscall" ) // LoadLocalSpecs reads an explicit development launch list, not a manifest or // installation catalog. It does not execute code or discover directories. func LoadLocalSpecs(path string) ([]Spec, error) { file, err := os.OpenFile(path, os.O_RDONLY|syscall.O_NONBLOCK, 0) if err != nil { return nil, err } defer file.Close() info, err := file.Stat() if err != nil { return nil, err } if !info.Mode().IsRegular() { return nil, fmt.Errorf("local tentacle list must be a regular file") } data, err := io.ReadAll(io.LimitReader(file, MaxFrameBytes+1)) if err != nil { return nil, err } if len(data) > MaxFrameBytes { return nil, ErrLimit } if err := validate_json(data); err != nil { return nil, err } var specs []Spec decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&specs); err != nil { return nil, err } if len(specs) > DefaultLimits().Processes { return nil, ErrLimit } seen := make(map[string]bool) for _, spec := range specs { if err := validate_spec(spec); err != nil { return nil, err } if seen[spec.ID] { return nil, fmt.Errorf("duplicate local tentacle ID") } seen[spec.ID] = true } return specs, nil } // DelegatedParent enables controllers only within the launcher's explicitly // delegated unit. The reader already lives in its own leaf; it is never moved // here. Other launchers can supply an already configured absolute parent. func DelegatedParent() (string, error) { data, err := os.ReadFile("/proc/self/cgroup") if err != nil { return "", err } parent, err := delegated_parent(string(data)) if err != nil { return "", err } if err := write_control(parent, "cgroup.subtree_control", "+cpu +memory +pids"); err != nil { return "", err } return parent, nil } func delegated_parent(membership string) (string, error) { for _, line := range strings.Split(membership, "\n") { if !strings.HasPrefix(line, "0::/") { continue } path := strings.TrimPrefix(line, "0::") if filepath.Clean(path) != path || filepath.Base(path) != "reader" || !strings.HasSuffix(filepath.Dir(path), ".service") { break } return filepath.Join("/sys/fs/cgroup", filepath.Dir(path)), nil } return "", fmt.Errorf("%w: reader requires a delegated service with DelegateSubgroup=reader", ErrContainment) }