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