github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/cgroups/cgroups_supported.go (about) 1 // +build linux 2 3 package cgroups 4 5 import ( 6 "bufio" 7 "fmt" 8 "os" 9 "path/filepath" 10 "strings" 11 "sync" 12 "syscall" 13 14 "github.com/pkg/errors" 15 "golang.org/x/sys/unix" 16 ) 17 18 var ( 19 isUnifiedOnce sync.Once 20 isUnified bool 21 isUnifiedErr error 22 ) 23 24 // IsCgroup2UnifiedMode returns whether we are running in cgroup 2 cgroup2 mode. 25 func IsCgroup2UnifiedMode() (bool, error) { 26 isUnifiedOnce.Do(func() { 27 var st syscall.Statfs_t 28 if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil { 29 isUnified, isUnifiedErr = false, err 30 } else { 31 isUnified, isUnifiedErr = st.Type == unix.CGROUP2_SUPER_MAGIC, nil 32 } 33 }) 34 return isUnified, isUnifiedErr 35 } 36 37 // UserOwnsCurrentSystemdCgroup checks whether the current EUID owns the 38 // current cgroup. 39 func UserOwnsCurrentSystemdCgroup() (bool, error) { 40 uid := os.Geteuid() 41 42 cgroup2, err := IsCgroup2UnifiedMode() 43 if err != nil { 44 return false, err 45 } 46 47 f, err := os.Open("/proc/self/cgroup") 48 if err != nil { 49 return false, err 50 } 51 defer f.Close() 52 53 scanner := bufio.NewScanner(f) 54 for scanner.Scan() { 55 line := scanner.Text() 56 parts := strings.SplitN(line, ":", 3) 57 58 if len(parts) < 3 { 59 continue 60 } 61 62 var cgroupPath string 63 64 if cgroup2 { 65 cgroupPath = filepath.Join(cgroupRoot, parts[2]) 66 } else { 67 if parts[1] != "name=systemd" { 68 continue 69 } 70 cgroupPath = filepath.Join(cgroupRoot, "systemd", parts[2]) 71 } 72 73 st, err := os.Stat(cgroupPath) 74 if err != nil { 75 return false, err 76 } 77 s := st.Sys() 78 if s == nil { 79 return false, fmt.Errorf("error stat cgroup path %s", cgroupPath) 80 } 81 82 if int(s.(*syscall.Stat_t).Uid) != uid { 83 return false, nil 84 } 85 } 86 if err := scanner.Err(); err != nil { 87 return false, errors.Wrapf(err, "parsing file /proc/self/cgroup") 88 } 89 return true, nil 90 }