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