1 package fs
2
3 import (
4 "errors"
5 "os"
6 "path/filepath"
7 "sync"
8
9 "golang.org/x/sys/unix"
10
11 "github.com/opencontainers/runc/libcontainer/cgroups"
12 "github.com/opencontainers/runc/libcontainer/configs"
13 "github.com/opencontainers/runc/libcontainer/utils"
14 )
15
16
17 var (
18 cgroupRootLock sync.Mutex
19 cgroupRoot string
20 )
21
22 const defaultCgroupRoot = "/sys/fs/cgroup"
23
24 func initPaths(cg *configs.Cgroup) (map[string]string, error) {
25 root, err := rootPath()
26 if err != nil {
27 return nil, err
28 }
29
30 inner, err := innerPath(cg)
31 if err != nil {
32 return nil, err
33 }
34
35 paths := make(map[string]string)
36 for _, sys := range subsystems {
37 name := sys.Name()
38 path, err := subsysPath(root, inner, name)
39 if err != nil {
40
41
42 if cgroups.IsNotFound(err) && (cg.SkipDevices || name != "devices") {
43 continue
44 }
45
46 return nil, err
47 }
48 paths[name] = path
49 }
50
51 return paths, nil
52 }
53
54 func tryDefaultCgroupRoot() string {
55 var st, pst unix.Stat_t
56
57
58 err := unix.Lstat(defaultCgroupRoot, &st)
59 if err != nil || st.Mode&unix.S_IFDIR == 0 {
60 return ""
61 }
62
63
64 err = unix.Lstat(filepath.Dir(defaultCgroupRoot), &pst)
65 if err != nil {
66 return ""
67 }
68
69 if st.Dev == pst.Dev {
70
71 return ""
72 }
73
74
75 var fst unix.Statfs_t
76 err = unix.Statfs(defaultCgroupRoot, &fst)
77 if err != nil || fst.Type != unix.TMPFS_MAGIC {
78 return ""
79 }
80
81
82 dir, err := os.Open(defaultCgroupRoot)
83 if err != nil {
84 return ""
85 }
86 defer dir.Close()
87 names, err := dir.Readdirnames(1)
88 if err != nil {
89 return ""
90 }
91 if len(names) < 1 {
92 return ""
93 }
94
95 err = unix.Statfs(filepath.Join(defaultCgroupRoot, names[0]), &fst)
96 if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC {
97 return ""
98 }
99
100 return defaultCgroupRoot
101 }
102
103
104 func rootPath() (string, error) {
105 cgroupRootLock.Lock()
106 defer cgroupRootLock.Unlock()
107
108 if cgroupRoot != "" {
109 return cgroupRoot, nil
110 }
111
112
113 cgroupRoot = tryDefaultCgroupRoot()
114 if cgroupRoot != "" {
115 return cgroupRoot, nil
116 }
117
118
119 mi, err := cgroups.GetCgroupMounts(false)
120 if err != nil {
121 return "", err
122 }
123 if len(mi) < 1 {
124 return "", errors.New("no cgroup mount found in mountinfo")
125 }
126
127
128
129 root := filepath.Dir(mi[0].Mountpoint)
130
131 if _, err := os.Stat(root); err != nil {
132 return "", err
133 }
134
135 cgroupRoot = root
136 return cgroupRoot, nil
137 }
138
139 func innerPath(c *configs.Cgroup) (string, error) {
140 if (c.Name != "" || c.Parent != "") && c.Path != "" {
141 return "", errors.New("cgroup: either Path or Name and Parent should be used")
142 }
143
144
145 innerPath := utils.CleanPath(c.Path)
146 if innerPath == "" {
147 cgParent := utils.CleanPath(c.Parent)
148 cgName := utils.CleanPath(c.Name)
149 innerPath = filepath.Join(cgParent, cgName)
150 }
151
152 return innerPath, nil
153 }
154
155 func subsysPath(root, inner, subsystem string) (string, error) {
156
157 if filepath.IsAbs(inner) {
158 mnt, err := cgroups.FindCgroupMountpoint(root, subsystem)
159
160 if err != nil {
161 return "", err
162 }
163
164
165 return filepath.Join(root, filepath.Base(mnt), inner), nil
166 }
167
168
169
170
171 parentPath, err := cgroups.GetOwnCgroupPath(subsystem)
172 if err != nil {
173 return "", err
174 }
175
176 return filepath.Join(parentPath, inner), nil
177 }
178
179 func apply(path string, pid int) error {
180 if path == "" {
181 return nil
182 }
183 if err := os.MkdirAll(path, 0o755); err != nil {
184 return err
185 }
186 return cgroups.WriteCgroupProc(path, pid)
187 }
188
View as plain text