]> git.proxmox.com Git - mirror_lxcfs.git/blob - src/sysfs_fuse.c
Merge pull request #402 from brauner/2020-04-28/fixes
[mirror_lxcfs.git] / src / sysfs_fuse.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #endif
6
7 #ifndef FUSE_USE_VERSION
8 #define FUSE_USE_VERSION 26
9 #endif
10
11 #define _FILE_OFFSET_BITS 64
12
13 #define __STDC_FORMAT_MACROS
14 #include <dirent.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <fuse.h>
18 #include <inttypes.h>
19 #include <libgen.h>
20 #include <pthread.h>
21 #include <sched.h>
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <wait.h>
30 #include <linux/magic.h>
31 #include <linux/sched.h>
32 #include <sys/epoll.h>
33 #include <sys/mman.h>
34 #include <sys/mount.h>
35 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <sys/syscall.h>
38 #include <sys/sysinfo.h>
39 #include <sys/vfs.h>
40
41 #include "bindings.h"
42 #include "memory_utils.h"
43 #include "cgroups/cgroup.h"
44 #include "config.h"
45 #include "sysfs_fuse.h"
46 #include "utils.h"
47
48 static int sys_devices_system_cpu_online_read(char *buf, size_t size,
49 off_t offset,
50 struct fuse_file_info *fi)
51 {
52 __do_free char *cg = NULL, *cpuset = NULL;
53 struct fuse_context *fc = fuse_get_context();
54 struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data;
55 struct file_info *d = INTTYPE_TO_PTR(fi->fh);
56 char *cache = d->buf;
57 bool use_view;
58
59 int max_cpus = 0;
60 pid_t initpid;
61 ssize_t total_len = 0;
62
63 if (offset) {
64 int left;
65
66 if (!d->cached)
67 return 0;
68
69 if (offset > d->size)
70 return -EINVAL;
71
72 left = d->size - offset;
73 total_len = left > size ? size : left;
74 memcpy(buf, cache + offset, total_len);
75
76 return total_len;
77 }
78
79 initpid = lookup_initpid_in_store(fc->pid);
80 if (initpid <= 1 || is_shared_pidns(initpid))
81 initpid = fc->pid;
82
83 cg = get_pid_cgroup(initpid, "cpuset");
84 if (!cg)
85 return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d);
86 prune_init_slice(cg);
87
88 cpuset = get_cpuset(cg);
89 if (!cpuset)
90 return 0;
91
92 if (cgroup_ops->can_use_cpuview(cgroup_ops) && opts && opts->use_cfs)
93 use_view = true;
94 else
95 use_view = false;
96 if (use_view)
97 max_cpus = max_cpu_count(cg);
98
99 if (use_view) {
100 if (max_cpus > 1)
101 total_len = snprintf(d->buf, d->buflen, "0-%d\n", max_cpus - 1);
102 else
103 total_len = snprintf(d->buf, d->buflen, "0\n");
104 } else if (cpuset) {
105 total_len = snprintf(d->buf, d->buflen, "%s\n", cpuset);
106 } else {
107 return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d);
108 }
109 if (total_len < 0 || total_len >= d->buflen)
110 return log_error(0, "Failed to write to cache");
111
112 d->size = (int)total_len;
113 d->cached = 1;
114
115 if (total_len > size)
116 total_len = size;
117
118 memcpy(buf, d->buf, total_len);
119
120 return total_len;
121 }
122
123 static off_t get_sysfile_size(const char *which)
124 {
125 __do_fclose FILE *f = NULL;
126 __do_free char *line = NULL;
127 size_t len = 0;
128 ssize_t sz, answer = 0;
129
130 f = fopen(which, "re");
131 if (!f)
132 return 0;
133
134 while ((sz = getline(&line, &len, f)) != -1)
135 answer += sz;
136
137 return answer;
138 }
139
140 __lxcfs_fuse_ops int sys_getattr(const char *path, struct stat *sb)
141 {
142 struct timespec now;
143
144 memset(sb, 0, sizeof(struct stat));
145 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
146 return -EINVAL;
147
148 sb->st_uid = sb->st_gid = 0;
149 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
150 if (strcmp(path, "/sys") == 0) {
151 sb->st_mode = S_IFDIR | 00555;
152 sb->st_nlink = 2;
153 return 0;
154 }
155
156 if (strcmp(path, "/sys/devices") == 0) {
157 sb->st_mode = S_IFDIR | 00555;
158 sb->st_nlink = 2;
159 return 0;
160 }
161
162 if (strcmp(path, "/sys/devices/system") == 0) {
163 sb->st_mode = S_IFDIR | 00555;
164 sb->st_nlink = 2;
165 return 0;
166 }
167
168 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
169 sb->st_mode = S_IFDIR | 00555;
170 sb->st_nlink = 2;
171 return 0;
172 }
173
174 if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
175 sb->st_size = 0;
176 sb->st_mode = S_IFREG | 00444;
177 sb->st_nlink = 1;
178 return 0;
179 }
180
181 return -ENOENT;
182 }
183
184 __lxcfs_fuse_ops int sys_readdir(const char *path, void *buf,
185 fuse_fill_dir_t filler, off_t offset,
186 struct fuse_file_info *fi)
187 {
188 if (strcmp(path, "/sys") == 0) {
189 if (filler(buf, ".", NULL, 0) != 0 ||
190 filler(buf, "..", NULL, 0) != 0 ||
191 filler(buf, "devices", NULL, 0) != 0)
192 return -ENOENT;
193
194 return 0;
195 }
196 if (strcmp(path, "/sys/devices") == 0) {
197 if (filler(buf, ".", NULL, 0) != 0 ||
198 filler(buf, "..", NULL, 0) != 0 ||
199 filler(buf, "system", NULL, 0) != 0)
200 return -ENOENT;
201
202 return 0;
203 }
204 if (strcmp(path, "/sys/devices/system") == 0) {
205 if (filler(buf, ".", NULL, 0) != 0 ||
206 filler(buf, "..", NULL, 0) != 0 ||
207 filler(buf, "cpu", NULL, 0) != 0)
208 return -ENOENT;
209
210 return 0;
211 }
212 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
213 if (filler(buf, ".", NULL, 0) != 0 ||
214 filler(buf, "..", NULL, 0) != 0 ||
215 filler(buf, "online", NULL, 0) != 0)
216 return -ENOENT;
217
218 return 0;
219 }
220
221 return 0;
222 }
223
224 __lxcfs_fuse_ops int sys_open(const char *path, struct fuse_file_info *fi)
225 {
226 __do_free struct file_info *info = NULL;
227 int type = -1;
228
229 if (strcmp(path, "/sys/devices") == 0)
230 type = LXC_TYPE_SYS_DEVICES;
231 if (strcmp(path, "/sys/devices/system") == 0)
232 type = LXC_TYPE_SYS_DEVICES_SYSTEM;
233 if (strcmp(path, "/sys/devices/system/cpu") == 0)
234 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
235 if (strcmp(path, "/sys/devices/system/cpu/online") == 0)
236 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
237 if (type == -1)
238 return -ENOENT;
239
240 info = malloc(sizeof(*info));
241 if (!info)
242 return -ENOMEM;
243
244 memset(info, 0, sizeof(*info));
245 info->type = type;
246
247 info->buflen = get_sysfile_size(path) + BUF_RESERVE_SIZE;
248
249 info->buf = malloc(info->buflen);
250 if (!info->buf)
251 return -ENOMEM;
252
253 memset(info->buf, 0, info->buflen);
254 /* set actual size to buffer size */
255 info->size = info->buflen;
256
257 fi->fh = PTR_TO_UINT64(move_ptr(info));
258 return 0;
259 }
260
261 __lxcfs_fuse_ops int sys_access(const char *path, int mask)
262 {
263 if (strcmp(path, "/sys") == 0 && access(path, R_OK) == 0)
264 return 0;
265
266 if (strcmp(path, "/sys/devices") == 0 && access(path, R_OK) == 0)
267 return 0;
268
269 if (strcmp(path, "/sys/devices/system") == 0 && access(path, R_OK) == 0)
270 return 0;
271
272 if (strcmp(path, "/sys/devices/system/cpu") == 0 &&
273 access(path, R_OK) == 0)
274 return 0;
275
276 /* these are all read-only */
277 if ((mask & ~R_OK) != 0)
278 return -EACCES;
279
280 return 0;
281 }
282
283 __lxcfs_fuse_ops int sys_release(const char *path, struct fuse_file_info *fi)
284 {
285 do_release_file_info(fi);
286 return 0;
287 }
288
289 __lxcfs_fuse_ops int sys_releasedir(const char *path, struct fuse_file_info *fi)
290 {
291 do_release_file_info(fi);
292 return 0;
293 }
294
295 __lxcfs_fuse_ops int sys_read(const char *path, char *buf, size_t size,
296 off_t offset, struct fuse_file_info *fi)
297 {
298 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
299
300 switch (f->type) {
301 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
302 if (liblxcfs_functional())
303 return sys_devices_system_cpu_online_read(buf, size, offset, fi);
304
305 return read_file_fuse_with_offset(LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH,
306 buf, size, offset, f);
307 case LXC_TYPE_SYS_DEVICES:
308 break;
309 case LXC_TYPE_SYS_DEVICES_SYSTEM:
310 break;
311 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
312 break;
313 }
314
315 return -EINVAL;
316 }