]> git.proxmox.com Git - mirror_lxcfs.git/blame - src/sysfs_fuse.c
Merge pull request #474 from brauner/2021-09-01.meson
[mirror_lxcfs.git] / src / sysfs_fuse.c
CommitLineData
db0463bf 1/* SPDX-License-Identifier: LGPL-2.1+ */
71f17cd2 2
1f5596dd
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE
5#endif
6
f834b6bf
SP
7#include "config.h"
8
26b717d0
ZL
9/* Taken over modified from the kernel sources. */
10#define NBITS 32 /* bits in uint32_t */
11#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
12#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, NBITS)
13
71f17cd2 14#define __STDC_FORMAT_MACROS
d9c820ee 15#include <ctype.h>
71f17cd2
YB
16#include <dirent.h>
17#include <errno.h>
18#include <fcntl.h>
71f17cd2
YB
19#include <inttypes.h>
20#include <libgen.h>
21#include <pthread.h>
22#include <sched.h>
23#include <stdbool.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <time.h>
29#include <unistd.h>
30#include <wait.h>
31#include <linux/magic.h>
32#include <linux/sched.h>
33#include <sys/epoll.h>
34#include <sys/mman.h>
35#include <sys/mount.h>
36#include <sys/param.h>
37#include <sys/socket.h>
38#include <sys/syscall.h>
39#include <sys/sysinfo.h>
40#include <sys/vfs.h>
41
e01afbb7
CB
42#include "sysfs_fuse.h"
43
71f17cd2 44#include "bindings.h"
700dd417 45#include "memory_utils.h"
77f4399a 46#include "cgroups/cgroup.h"
ec2043ed 47#include "lxcfs_fuse_compat.h"
1d81c6a6 48#include "utils.h"
71f17cd2 49
26b717d0
ZL
50static ssize_t get_max_cpus(char *cpulist)
51{
52 char *c1, *c2;
53 char *maxcpus = cpulist;
54 size_t cpus = 0;
55
56 c1 = strrchr(maxcpus, ',');
57 if (c1)
58 c1++;
59
60 c2 = strrchr(maxcpus, '-');
61 if (c2)
62 c2++;
63
64 if (!c1 && !c2)
65 c1 = maxcpus;
66 else if (c1 > c2)
67 c2 = c1;
68 else if (c1 < c2)
69 c1 = c2;
70 else if (!c1 && c2)
71 c1 = c2;
72
73 errno = 0;
74 cpus = strtoul(c1, NULL, 0);
75 if (errno != 0)
76 return -1;
77
78 return cpus;
79}
80
81static void set_bit(unsigned bit, uint32_t *bitarr)
82{
83 bitarr[bit / NBITS] |= (1 << (bit % NBITS));
84}
85
86static bool is_set(unsigned bit, uint32_t *bitarr)
87{
88 return (bitarr[bit / NBITS] & (1 << (bit % NBITS))) != 0;
89}
90
91/* Create cpumask from cpulist aka turn:
92 *
93 * 0,2-3
94 *
95 * into bit array
96 *
97 * 1 0 1 1
98 */
99static uint32_t *lxc_cpumask(char *buf, size_t nbits)
100{
101 __do_free uint32_t *bitarr = NULL;
102 char *token;
103 size_t arrlen;
104
105 arrlen = BITS_TO_LONGS(nbits);
106 bitarr = calloc(arrlen, sizeof(uint32_t));
107 if (!bitarr)
108 return ret_set_errno(NULL, ENOMEM);
109
110 lxc_iterate_parts(token, buf, ",") {
111 errno = 0;
112 unsigned end, start;
113 char *range;
114
115 start = strtoul(token, NULL, 0);
116 end = start;
117 range = strchr(token, '-');
118 if (range)
119 end = strtoul(range + 1, NULL, 0);
120
121 if (!(start <= end))
122 return ret_set_errno(NULL, EINVAL);
123
124 if (end >= nbits)
125 return ret_set_errno(NULL, EINVAL);
126
127 while (start <= end)
128 set_bit(start++, bitarr);
129 }
130
131 return move_ptr(bitarr);
132}
133
71f17cd2
YB
134static int sys_devices_system_cpu_online_read(char *buf, size_t size,
135 off_t offset,
136 struct fuse_file_info *fi)
137{
700dd417 138 __do_free char *cg = NULL, *cpuset = NULL;
71f17cd2 139 struct fuse_context *fc = fuse_get_context();
8044f626 140 struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data;
99b183fb 141 struct file_info *d = INTTYPE_TO_PTR(fi->fh);
71f17cd2 142 char *cache = d->buf;
71f17cd2
YB
143 bool use_view;
144
145 int max_cpus = 0;
146 pid_t initpid;
147 ssize_t total_len = 0;
148
149 if (offset) {
3cf1e562 150 size_t left;
700dd417 151
71f17cd2
YB
152 if (!d->cached)
153 return 0;
700dd417 154
71f17cd2
YB
155 if (offset > d->size)
156 return -EINVAL;
700dd417
CB
157
158 left = d->size - offset;
71f17cd2
YB
159 total_len = left > size ? size : left;
160 memcpy(buf, cache + offset, total_len);
700dd417 161
71f17cd2
YB
162 return total_len;
163 }
164
165 initpid = lookup_initpid_in_store(fc->pid);
a9f0d623 166 if (initpid <= 1 || is_shared_pidns(initpid))
71f17cd2 167 initpid = fc->pid;
a9f0d623 168
71f17cd2
YB
169 cg = get_pid_cgroup(initpid, "cpuset");
170 if (!cg)
5fbea8a6 171 return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d);
71f17cd2
YB
172 prune_init_slice(cg);
173
174 cpuset = get_cpuset(cg);
175 if (!cpuset)
700dd417 176 return 0;
71f17cd2 177
8044f626
CB
178 if (cgroup_ops->can_use_cpuview(cgroup_ops) && opts && opts->use_cfs)
179 use_view = true;
180 else
181 use_view = false;
26b717d0 182
71f17cd2
YB
183 if (use_view)
184 max_cpus = max_cpu_count(cg);
185
b3c85f5d
CB
186 if (use_view) {
187 if (max_cpus > 1)
188 total_len = snprintf(d->buf, d->buflen, "0-%d\n", max_cpus - 1);
189 else
190 total_len = snprintf(d->buf, d->buflen, "0\n");
b3c85f5d 191 } else {
133cba47 192 total_len = snprintf(d->buf, d->buflen, "%s\n", cpuset);
b3c85f5d 193 }
cf07826e
CB
194 if (total_len < 0 || total_len >= d->buflen)
195 return log_error(0, "Failed to write to cache");
71f17cd2
YB
196
197 d->size = (int)total_len;
198 d->cached = 1;
199
3cf1e562 200 if ((size_t)total_len > size)
71f17cd2
YB
201 total_len = size;
202
203 memcpy(buf, d->buf, total_len);
700dd417 204
71f17cd2
YB
205 return total_len;
206}
207
26b717d0
ZL
208static int filler_sys_devices_system_cpu(const char *path, void *buf,
209 fuse_fill_dir_t filler)
210{
211 __do_free uint32_t *cpumask = NULL;
212 __do_free char *cg = NULL, *cpuset = NULL;
213 __do_closedir DIR *dir = NULL;
214 struct dirent *dirent;
215 struct fuse_context *fc = fuse_get_context();
216 pid_t initpid;
217 ssize_t max_cpus;
26b717d0
ZL
218
219 initpid = lookup_initpid_in_store(fc->pid);
220 if (initpid <= 1 || is_shared_pidns(initpid))
221 initpid = fc->pid;
222
223 cg = get_pid_cgroup(initpid, "cpuset");
224 if (!cg)
225 return 0;
226 prune_init_slice(cg);
227
228 cpuset = get_cpuset(cg);
229 if (!cpuset)
230 return 0;
231
232 max_cpus = get_max_cpus(cpuset);
233 if (max_cpus < 0 || max_cpus >= (INT_MAX - 1))
234 return -1;
235 max_cpus++;
236
237 cpumask = lxc_cpumask(cpuset, max_cpus);
238 if (!cpumask)
239 return -errno;
240
3cf1e562 241 for (ssize_t i = 0; i < max_cpus; i++) {
26b717d0 242 int ret;
d9c820ee 243 char cpu[100];
26b717d0
ZL
244
245 if (!is_set(i, cpumask))
246 continue;
247
248 ret = snprintf(cpu, sizeof(cpu), "cpu%ld", i);
3cf1e562 249 if (ret < 0 || (size_t)ret >= sizeof(cpu))
26b717d0
ZL
250 continue;
251
252 if (DIR_FILLER(filler, buf, cpu, NULL, 0) != 0)
253 return -ENOENT;
254 }
255
256 dir = opendir(path);
257 if (!dir)
258 return -ENOENT;
259
260 while ((dirent = readdir(dir))) {
d9c820ee
CB
261 char *entry = dirent->d_name;
262
263 if (strlen(entry) <= 3)
264 continue;
265 entry += 3;
266
267 /* Don't emit entries we already filtered above. */
268 if (isdigit(*entry))
26b717d0
ZL
269 continue;
270
271 if (DIR_FILLER(filler, buf, dirent->d_name, NULL, 0) != 0)
272 return -ENOENT;
273 }
274
275 return 0;
276}
277
d9c820ee 278static int get_st_mode(const char *path, mode_t *mode)
26b717d0
ZL
279{
280 struct stat sb;
281 int ret;
282
283 ret = lstat(path, &sb);
284 if (ret < 0)
285 return -ENOENT;
286
d9c820ee
CB
287 *mode = sb.st_mode;
288 return 0;
26b717d0
ZL
289}
290
71f17cd2
YB
291static off_t get_sysfile_size(const char *which)
292{
700dd417
CB
293 __do_fclose FILE *f = NULL;
294 __do_free char *line = NULL;
71f17cd2
YB
295 size_t len = 0;
296 ssize_t sz, answer = 0;
297
700dd417 298 f = fopen(which, "re");
71f17cd2
YB
299 if (!f)
300 return 0;
301
302 while ((sz = getline(&line, &len, f)) != -1)
303 answer += sz;
71f17cd2
YB
304
305 return answer;
306}
307
0d5383b7
CB
308static int sys_getattr_legacy(const char *path, struct stat *sb)
309{
310 struct timespec now;
311
312 memset(sb, 0, sizeof(struct stat));
313 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
314 return -EINVAL;
315
316 sb->st_uid = sb->st_gid = 0;
317 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
318 if (strcmp(path, "/sys") == 0) {
319 sb->st_mode = S_IFDIR | 00555;
320 sb->st_nlink = 2;
321 return 0;
322 }
323
324 if (strcmp(path, "/sys/devices") == 0) {
325 sb->st_mode = S_IFDIR | 00555;
326 sb->st_nlink = 2;
327 return 0;
328 }
329
330 if (strcmp(path, "/sys/devices/system") == 0) {
331 sb->st_mode = S_IFDIR | 00555;
332 sb->st_nlink = 2;
333 return 0;
334 }
335
336 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
337 sb->st_mode = S_IFDIR | 00555;
338 sb->st_nlink = 2;
339 return 0;
340 }
341
342 if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
343 sb->st_size = get_sysfile_size (path);
344 sb->st_mode = S_IFREG | 00444;
345 sb->st_nlink = 1;
346 return 0;
347 }
348
349 return -ENOENT;
350}
351
2d7bcab7 352__lxcfs_fuse_ops int sys_getattr(const char *path, struct stat *sb)
71f17cd2 353{
d9c820ee 354 int ret;
71f17cd2 355 struct timespec now;
26b717d0
ZL
356 mode_t st_mode;
357
358 if (!liblxcfs_functional())
359 return -EIO;
71f17cd2 360
0d5383b7
CB
361 if (!liblxcfs_can_use_sys_cpu())
362 return sys_getattr_legacy(path, sb);
363
71f17cd2
YB
364 memset(sb, 0, sizeof(struct stat));
365 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
366 return -EINVAL;
cf07826e 367
71f17cd2
YB
368 sb->st_uid = sb->st_gid = 0;
369 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
cf07826e 370
d9c820ee
CB
371 ret = get_st_mode(path, &st_mode);
372 if (ret)
26b717d0 373 return -ENOENT;
cf07826e 374
26b717d0
ZL
375 if (S_ISDIR(st_mode)) {
376 sb->st_mode = st_mode;
71f17cd2
YB
377 sb->st_nlink = 2;
378 return 0;
379 }
cf07826e 380
26b717d0
ZL
381 if (S_ISREG(st_mode) || S_ISLNK(st_mode)) {
382 sb->st_size = get_sysfile_size(path);
383 sb->st_mode = st_mode;
71f17cd2
YB
384 sb->st_nlink = 1;
385 return 0;
386 }
387
388 return -ENOENT;
389}
390
0d5383b7
CB
391__lxcfs_fuse_ops int sys_release(const char *path, struct fuse_file_info *fi)
392{
393 do_release_file_info(fi);
394 return 0;
395}
396
397__lxcfs_fuse_ops int sys_releasedir(const char *path, struct fuse_file_info *fi)
398{
399 do_release_file_info(fi);
400 return 0;
401}
402
403__lxcfs_fuse_ops int sys_write(const char *path, const char *buf, size_t size,
404 off_t offset, struct fuse_file_info *fi)
26b717d0
ZL
405{
406 __do_close int fd = -EBADF;
407 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
408
409 if (!liblxcfs_functional())
410 return -EIO;
411
412 if (f->type != LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE)
413 return -EINVAL;
414
415 fd = open(path, O_WRONLY | O_CLOEXEC);
416 if (fd == -1)
417 return -errno;
418
419 return pwrite(fd, buf, size, offset);
420}
421
0d5383b7
CB
422static int sys_readdir_legacy(const char *path, void *buf, fuse_fill_dir_t filler,
423 off_t offset, struct fuse_file_info *fi)
424{
425 if (strcmp(path, "/sys") == 0) {
426 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
427 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
428 DIR_FILLER(filler, buf, "devices", NULL, 0) != 0)
429 return -ENOENT;
430
431 return 0;
432 }
433 if (strcmp(path, "/sys/devices") == 0) {
434 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
435 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
436 DIR_FILLER(filler, buf, "system", NULL, 0) != 0)
437 return -ENOENT;
438
439 return 0;
440 }
441 if (strcmp(path, "/sys/devices/system") == 0) {
442 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
443 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
444 DIR_FILLER(filler, buf, "cpu", NULL, 0) != 0)
445 return -ENOENT;
446
447 return 0;
448 }
449 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
450 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
451 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
452 DIR_FILLER(filler, buf, "online", NULL, 0) != 0)
453 return -ENOENT;
454
455 return 0;
456 }
457
458 return 0;
459}
460
2d7bcab7 461__lxcfs_fuse_ops int sys_readdir(const char *path, void *buf,
0d5383b7
CB
462 fuse_fill_dir_t filler, off_t offset,
463 struct fuse_file_info *fi)
71f17cd2 464{
26b717d0
ZL
465 __do_closedir DIR *dir = NULL;
466 struct dirent *dirent;
467 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
cf07826e 468
26b717d0
ZL
469 if (!liblxcfs_functional())
470 return -EIO;
cf07826e 471
0d5383b7
CB
472 if (!liblxcfs_can_use_sys_cpu())
473 return sys_readdir_legacy(path, buf, filler, offset, fi);
474
475 /*
476 * When we reload LXCFS and we don't load the lxcfs binary itself
477 * changes to such functions as lxcfs_opendir() aren't reflected so
478 * sys_opendir() doesn't run but sys_readdir() does. We need to account
479 * for that here.
480 */
481 if (!f)
482 return -EIO;
483
26b717d0
ZL
484 switch (f->type) {
485 case LXC_TYPE_SYS: {
486 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
487 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
488 DIR_FILLER(filler, buf, "devices", NULL, 0) != 0)
489 return -ENOENT;
cf07826e 490
26b717d0
ZL
491 return 0;
492 }
493 case LXC_TYPE_SYS_DEVICES: {
494 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
495 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
496 DIR_FILLER(filler, buf, "system", NULL, 0) != 0)
497 return -ENOENT;
cf07826e 498
26b717d0
ZL
499 return 0;
500 }
501 case LXC_TYPE_SYS_DEVICES_SYSTEM: {
502 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
503 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
504 DIR_FILLER(filler, buf, "cpu", NULL, 0) != 0)
505 return -ENOENT;
506
507 return 0;
508 }
509 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
76a883b0
CB
510 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
511 DIR_FILLER(filler, buf, "..", NULL, 0) != 0)
512 return -ENOENT;
513
514 return filler_sys_devices_system_cpu(path, buf, filler);
26b717d0
ZL
515 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBDIR: {
516 dir = opendir(path);
517 if (!dir)
518 return -ENOENT;
519
520 while ((dirent = readdir(dir))) {
521 if (DIR_FILLER(filler, buf, dirent->d_name, NULL, 0) != 0)
522 return -ENOENT;
523 }
524
525 return 0;
526 }
71f17cd2
YB
527 }
528
26b717d0 529 return -EINVAL;
71f17cd2
YB
530}
531
26b717d0
ZL
532__lxcfs_fuse_ops int sys_readlink(const char *path, char *buf, size_t size)
533{
3cf1e562 534 ssize_t ret;
26b717d0
ZL
535
536 if (!liblxcfs_functional())
537 return -EIO;
538
3cf1e562 539 ret = readlink(path, buf, size);
26b717d0
ZL
540 if (ret < 0)
541 return -errno;
3cf1e562
CB
542
543 if ((size_t)ret > size)
26b717d0
ZL
544 return -1;
545
546 buf[ret] = '\0';
547
548 return 0;
549}
0d5383b7
CB
550
551static int sys_open_legacy(const char *path, struct fuse_file_info *fi)
552{
553 __do_free struct file_info *info = NULL;
554 int type = -1;
555
556 if (strcmp(path, "/sys/devices") == 0)
557 type = LXC_TYPE_SYS_DEVICES;
558 if (strcmp(path, "/sys/devices/system") == 0)
559 type = LXC_TYPE_SYS_DEVICES_SYSTEM;
560 if (strcmp(path, "/sys/devices/system/cpu") == 0)
561 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
562 if (strcmp(path, "/sys/devices/system/cpu/online") == 0)
563 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
564 if (type == -1)
565 return -ENOENT;
566
567 info = malloc(sizeof(*info));
568 if (!info)
569 return -ENOMEM;
570
571 memset(info, 0, sizeof(*info));
572 info->type = type;
573
574 info->buflen = get_sysfile_size(path) + BUF_RESERVE_SIZE;
575
576 info->buf = malloc(info->buflen);
577 if (!info->buf)
578 return -ENOMEM;
579
580 memset(info->buf, 0, info->buflen);
581 /* set actual size to buffer size */
582 info->size = info->buflen;
583
584 fi->fh = PTR_TO_UINT64(move_ptr(info));
585 return 0;
586}
587
2d7bcab7 588__lxcfs_fuse_ops int sys_open(const char *path, struct fuse_file_info *fi)
71f17cd2 589{
700dd417 590 __do_free struct file_info *info = NULL;
71f17cd2 591 int type = -1;
71f17cd2 592
26b717d0
ZL
593 if (!liblxcfs_functional())
594 return -EIO;
595
0d5383b7
CB
596 if (!liblxcfs_can_use_sys_cpu())
597 return sys_open_legacy(path, fi);
598
d9c820ee 599 if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
71f17cd2 600 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
d9c820ee
CB
601 } else if (strncmp(path, "/sys/devices/system/cpu/",
602 STRLITERALLEN("/sys/devices/system/cpu/")) == 0) {
603 int ret;
604 mode_t st_mode;
605
606 ret = get_st_mode(path, &st_mode);
607 if (ret)
608 return ret;
609
610 if (S_ISREG(st_mode))
611 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE;
612 }
71f17cd2
YB
613 if (type == -1)
614 return -ENOENT;
615
616 info = malloc(sizeof(*info));
617 if (!info)
618 return -ENOMEM;
619
620 memset(info, 0, sizeof(*info));
621 info->type = type;
622
623 info->buflen = get_sysfile_size(path) + BUF_RESERVE_SIZE;
700dd417
CB
624
625 info->buf = malloc(info->buflen);
626 if (!info->buf)
627 return -ENOMEM;
628
71f17cd2
YB
629 memset(info->buf, 0, info->buflen);
630 /* set actual size to buffer size */
631 info->size = info->buflen;
632
700dd417 633 fi->fh = PTR_TO_UINT64(move_ptr(info));
71f17cd2
YB
634 return 0;
635}
636
26b717d0 637__lxcfs_fuse_ops int sys_opendir(const char *path, struct fuse_file_info *fi)
71f17cd2 638{
26b717d0
ZL
639 __do_free struct file_info *dir_info = NULL;
640 int type = -1;
cf07826e 641
26b717d0
ZL
642 if (!liblxcfs_functional())
643 return -EIO;
cf07826e 644
d9c820ee 645 if (strcmp(path, "/sys") == 0) {
26b717d0 646 type = LXC_TYPE_SYS;
d9c820ee 647 } else if (strcmp(path, "/sys/devices") == 0) {
26b717d0 648 type = LXC_TYPE_SYS_DEVICES;
d9c820ee 649 } else if (strcmp(path, "/sys/devices/system") == 0) {
26b717d0 650 type = LXC_TYPE_SYS_DEVICES_SYSTEM;
d9c820ee 651 } else if (strcmp(path, "/sys/devices/system/cpu") == 0) {
26b717d0 652 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
d9c820ee
CB
653 } else if (strncmp(path, "/sys/devices/system/cpu/",
654 STRLITERALLEN("/sys/devices/system/cpu/")) == 0) {
655 int ret;
656 mode_t st_mode;
657
658 ret = get_st_mode(path, &st_mode);
659 if (ret)
660 return ret;
661
662 if (S_ISDIR(st_mode))
663 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBDIR;
664 }
26b717d0
ZL
665 if (type == -1)
666 return -ENOENT;
cf07826e 667
26b717d0
ZL
668 dir_info = malloc(sizeof(*dir_info));
669 if (!dir_info)
670 return -ENOMEM;
cf07826e 671
26b717d0
ZL
672 memset(dir_info, 0, sizeof(*dir_info));
673 dir_info->type = type;
674 dir_info->buf = NULL;
675 dir_info->file = NULL;
676 dir_info->buflen = 0;
cf07826e 677
26b717d0 678 fi->fh = PTR_TO_UINT64(move_ptr(dir_info));
71f17cd2
YB
679 return 0;
680}
681
0d5383b7
CB
682static int sys_access_legacy(const char *path, int mask)
683{
684 if (strcmp(path, "/sys") == 0 && access(path, R_OK) == 0)
685 return 0;
686
687 if (strcmp(path, "/sys/devices") == 0 && access(path, R_OK) == 0)
688 return 0;
689
690 if (strcmp(path, "/sys/devices/system") == 0 && access(path, R_OK) == 0)
691 return 0;
692
693 if (strcmp(path, "/sys/devices/system/cpu") == 0 &&
694 access(path, R_OK) == 0)
695 return 0;
696
697 /* these are all read-only */
698 if ((mask & ~R_OK) != 0)
699 return -EACCES;
700
701 return 0;
702}
703
26b717d0
ZL
704__lxcfs_fuse_ops int sys_access(const char *path, int mask)
705{
706 if (!liblxcfs_functional())
707 return -EIO;
708
0d5383b7
CB
709 if (!liblxcfs_can_use_sys_cpu())
710 return sys_access_legacy(path, mask);
711
26b717d0
ZL
712 return access(path, mask);
713}
714
0d5383b7
CB
715static int sys_read_legacy(const char *path, char *buf, size_t size,
716 off_t offset, struct fuse_file_info *fi)
71f17cd2 717{
0d5383b7 718 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
71f17cd2 719
0d5383b7
CB
720 switch (f->type) {
721 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
722 if (liblxcfs_functional())
723 return sys_devices_system_cpu_online_read(buf, size, offset, fi);
724
725 return read_file_fuse_with_offset(LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH,
726 buf, size, offset, f);
727 case LXC_TYPE_SYS_DEVICES:
728 break;
729 case LXC_TYPE_SYS_DEVICES_SYSTEM:
730 break;
731 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
732 break;
733 }
734
735 return -EINVAL;
71f17cd2
YB
736}
737
2d7bcab7 738__lxcfs_fuse_ops int sys_read(const char *path, char *buf, size_t size,
0d5383b7 739 off_t offset, struct fuse_file_info *fi)
71f17cd2 740{
99b183fb 741 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
71f17cd2 742
26b717d0
ZL
743 if (!liblxcfs_functional())
744 return -EIO;
745
0d5383b7
CB
746 if (!liblxcfs_can_use_sys_cpu())
747 return sys_read_legacy(path, buf, size, offset, fi);
748
71f17cd2 749 switch (f->type) {
36817cdd 750 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
26b717d0
ZL
751 return sys_devices_system_cpu_online_read(buf, size, offset, fi);
752 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE:
753 return read_file_fuse_with_offset(path, buf, size, offset, f);
71f17cd2 754 }
700dd417
CB
755
756 return -EINVAL;
71f17cd2 757}