github.com/rigado/snapd@v2.42.5-go-mod+incompatible/sandbox/cgroup/cgroup.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package cgroup 21 22 import ( 23 "fmt" 24 "path/filepath" 25 "syscall" 26 27 "github.com/snapcore/snapd/dirs" 28 ) 29 30 const ( 31 // From golang.org/x/sys/unix 32 cgroup2SuperMagic = 0x63677270 33 34 // The only cgroup path we expect, for v2 this is where the unified 35 // hierarchy is mounted, for v1 this is usually a tmpfs mount, under 36 // which the controller-hierarchies are mounted 37 expectedMountPoint = "/sys/fs/cgroup" 38 ) 39 40 const ( 41 // Separate block, because iota is fun 42 Unknown = iota 43 V1 44 V2 45 ) 46 47 var ( 48 probeVersion = Unknown 49 probeErr error = nil 50 ) 51 52 func init() { 53 probeVersion, probeErr = probeCgroupVersion() 54 } 55 56 var fsTypeForPath = fsTypeForPathImpl 57 58 func fsTypeForPathImpl(path string) (int64, error) { 59 var statfs syscall.Statfs_t 60 if err := syscall.Statfs(path, &statfs); err != nil { 61 return 0, fmt.Errorf("cannot statfs path: %v", err) 62 } 63 // Typs is int32 on 386, use explicit conversion to keep the code 64 // working for both 65 return int64(statfs.Type), nil 66 } 67 68 // ProcPidPath returns the path to the cgroup file under /proc for the given 69 // process id. 70 func ProcPidPath(pid int) string { 71 return filepath.Join(dirs.GlobalRootDir, fmt.Sprintf("proc/%v/cgroup", pid)) 72 } 73 74 // ControllerPathV1 returns the path to given controller assuming cgroup v1 75 // hierarchy 76 func ControllerPathV1(controller string) string { 77 return filepath.Join(dirs.GlobalRootDir, expectedMountPoint, controller) 78 } 79 80 func probeCgroupVersion() (version int, err error) { 81 cgroupMount := filepath.Join(dirs.GlobalRootDir, expectedMountPoint) 82 typ, err := fsTypeForPath(cgroupMount) 83 if err != nil { 84 return Unknown, fmt.Errorf("cannot determine filesystem type: %v", err) 85 } 86 if typ == cgroup2SuperMagic { 87 return V2, nil 88 } 89 return V1, nil 90 } 91 92 // IsUnified returns true when a unified cgroup hierarchy is in use 93 func IsUnified() bool { 94 version, _ := Version() 95 return version == V2 96 } 97 98 // Version returns the detected cgroup version 99 func Version() (int, error) { 100 return probeVersion, probeErr 101 } 102 103 // MockVersion sets the reported version of cgroup support. For use in testing only 104 func MockVersion(mockVersion int, mockErr error) (restore func()) { 105 oldVersion, oldErr := probeVersion, probeErr 106 probeVersion, probeErr = mockVersion, mockErr 107 return func() { 108 probeVersion, probeErr = oldVersion, oldErr 109 } 110 }