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