]> git.proxmox.com Git - mirror_lxcfs.git/blame - src/sysfs_fuse.c
sysfs: cleanup sys_devices_system_cpu_online_getsize
[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
07e79d35 40static off_t get_sysfile_size(const char *which);
26b717d0
ZL
41/* Create cpumask from cpulist aka turn:
42 *
43 * 0,2-3
44 *
45 * into bit array
46 *
47 * 1 0 1 1
48 */
a3c8d33c 49static int lxc_cpumask(char *buf, __u32 **bitarr, __u32 *last_set_bit)
26b717d0 50{
a3c8d33c
CB
51 __do_free __u32 *arr_u32 = NULL;
52 __u32 cur_last_set_bit = 0, nbits = 256;
53 __u32 nr_u32;
26b717d0 54 char *token;
26b717d0 55
a3c8d33c
CB
56 nr_u32 = BITS_TO_LONGS(nbits);
57 arr_u32 = zalloc(nr_u32 * sizeof(__u32));
58 if (!arr_u32)
59 return ret_errno(ENOMEM);
26b717d0
ZL
60
61 lxc_iterate_parts(token, buf, ",") {
a3c8d33c
CB
62 __u32 last_bit, first_bit;
63 char *range;
64
26b717d0 65 errno = 0;
a3c8d33c
CB
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
103static 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;
26b717d0
ZL
111 char *range;
112
a3c8d33c
CB
113 errno = 0;
114 first_bit = strtoul(token, NULL, 0);
115 last_bit = first_bit;
26b717d0
ZL
116 range = strchr(token, '-');
117 if (range)
a3c8d33c
CB
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 }
26b717d0 124
a3c8d33c
CB
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"
149static 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 }
26b717d0 166
a3c8d33c
CB
167 if (file_exists(__OFFLINE_CPUS)) {
168 offlinecpus = read_file_at(-EBADF, __OFFLINE_CPUS, PROTECT_OPEN);
169 if (!offlinecpus)
170 return -1;
26b717d0 171
a3c8d33c
CB
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");
26b717d0
ZL
176 }
177
a3c8d33c
CB
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;
26b717d0
ZL
193}
194
07e79d35 195static 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 }
d0aeaf06 224 if (total_len < 0 || (size_t)total_len >= buflen)
07e79d35 225 return log_error(0, "Failed to write to cache");
226
227 return total_len;
228}
229
71f17cd2
YB
230static int sys_devices_system_cpu_online_read(char *buf, size_t size,
231 off_t offset,
232 struct fuse_file_info *fi)
233{
07e79d35 234 __do_free char *cg = NULL;
71f17cd2 235 struct fuse_context *fc = fuse_get_context();
99b183fb 236 struct file_info *d = INTTYPE_TO_PTR(fi->fh);
71f17cd2 237 char *cache = d->buf;
71f17cd2
YB
238 pid_t initpid;
239 ssize_t total_len = 0;
240
241 if (offset) {
3cf1e562 242 size_t left;
700dd417 243
71f17cd2
YB
244 if (!d->cached)
245 return 0;
700dd417 246
71f17cd2
YB
247 if (offset > d->size)
248 return -EINVAL;
700dd417
CB
249
250 left = d->size - offset;
71f17cd2
YB
251 total_len = left > size ? size : left;
252 memcpy(buf, cache + offset, total_len);
700dd417 253
71f17cd2
YB
254 return total_len;
255 }
256
257 initpid = lookup_initpid_in_store(fc->pid);
a9f0d623 258 if (initpid <= 1 || is_shared_pidns(initpid))
71f17cd2 259 initpid = fc->pid;
a9f0d623 260
71f17cd2
YB
261 cg = get_pid_cgroup(initpid, "cpuset");
262 if (!cg)
5fbea8a6 263 return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d);
71f17cd2
YB
264 prune_init_slice(cg);
265
07e79d35 266 total_len = do_cpuset_read(cg, d->buf, d->buflen);
71f17cd2
YB
267
268 d->size = (int)total_len;
269 d->cached = 1;
270
3cf1e562 271 if ((size_t)total_len > size)
71f17cd2
YB
272 total_len = size;
273
274 memcpy(buf, d->buf, total_len);
700dd417 275
71f17cd2
YB
276 return total_len;
277}
278
d0aeaf06 279static int sys_devices_system_cpu_online_getsize(const char *path)
07e79d35 280{
d0aeaf06 281 __do_free char *cg = NULL;
07e79d35 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
26b717d0
ZL
299static int filler_sys_devices_system_cpu(const char *path, void *buf,
300 fuse_fill_dir_t filler)
301{
a3c8d33c 302 __do_free __u32 *bitarr = NULL;
26b717d0 303 __do_free char *cg = NULL, *cpuset = NULL;
9ad7d659 304 __do_closedir DIR *dirp = NULL;
26b717d0 305 struct fuse_context *fc = fuse_get_context();
a3c8d33c
CB
306 __u32 last_set_bit = 0;
307 int ret;
308 struct dirent *dirent;
26b717d0 309 pid_t initpid;
26b717d0
ZL
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
a3c8d33c
CB
324 ret = cpumask(cpuset, &bitarr, &last_set_bit);
325 if (ret)
326 return ret;
26b717d0 327
9ad7d659
CBM
328 dirp = opendir(path);
329 if (!dirp)
330 return -ENOENT;
331
a3c8d33c 332 for (__u32 bit = 0; bit <= last_set_bit; bit++) {
d9c820ee 333 char cpu[100];
26b717d0 334
a3c8d33c 335 if (!is_set(bit, bitarr))
26b717d0
ZL
336 continue;
337
a3c8d33c 338 ret = snprintf(cpu, sizeof(cpu), "cpu%u", bit);
3cf1e562 339 if (ret < 0 || (size_t)ret >= sizeof(cpu))
26b717d0
ZL
340 continue;
341
9ad7d659 342 if (dir_fillerat(filler, dirp, cpu, buf, 0) != 0)
26b717d0
ZL
343 return -ENOENT;
344 }
345
9ad7d659 346 while ((dirent = readdir(dirp))) {
d9c820ee
CB
347 char *entry = dirent->d_name;
348
ece0d2bb
SG
349 if (strlen(entry) > 3) {
350 entry += 3;
d9c820ee 351
ece0d2bb
SG
352 /* Don't emit entries we already filtered above. */
353 if (isdigit(*entry))
354 continue;
355 }
26b717d0 356
9ad7d659 357 if (dirent_fillerat(filler, dirp, dirent, buf, 0) != 0)
26b717d0
ZL
358 return -ENOENT;
359 }
360
361 return 0;
362}
363
d9c820ee 364static int get_st_mode(const char *path, mode_t *mode)
26b717d0
ZL
365{
366 struct stat sb;
367 int ret;
368
369 ret = lstat(path, &sb);
370 if (ret < 0)
371 return -ENOENT;
372
d9c820ee
CB
373 *mode = sb.st_mode;
374 return 0;
26b717d0
ZL
375}
376
71f17cd2
YB
377static off_t get_sysfile_size(const char *which)
378{
700dd417
CB
379 __do_fclose FILE *f = NULL;
380 __do_free char *line = NULL;
71f17cd2
YB
381 size_t len = 0;
382 ssize_t sz, answer = 0;
383
700dd417 384 f = fopen(which, "re");
71f17cd2
YB
385 if (!f)
386 return 0;
387
388 while ((sz = getline(&line, &len, f)) != -1)
389 answer += sz;
71f17cd2
YB
390
391 return answer;
392}
393
0d5383b7
CB
394static 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) {
d0aeaf06 429 sb->st_size = sys_devices_system_cpu_online_getsize(path);
0d5383b7
CB
430 sb->st_mode = S_IFREG | 00444;
431 sb->st_nlink = 1;
432 return 0;
433 }
434
435 return -ENOENT;
436}
437
2d7bcab7 438__lxcfs_fuse_ops int sys_getattr(const char *path, struct stat *sb)
71f17cd2 439{
d9c820ee 440 int ret;
71f17cd2 441 struct timespec now;
26b717d0
ZL
442 mode_t st_mode;
443
444 if (!liblxcfs_functional())
445 return -EIO;
71f17cd2 446
0d5383b7
CB
447 if (!liblxcfs_can_use_sys_cpu())
448 return sys_getattr_legacy(path, sb);
449
71f17cd2
YB
450 memset(sb, 0, sizeof(struct stat));
451 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
452 return -EINVAL;
cf07826e 453
71f17cd2
YB
454 sb->st_uid = sb->st_gid = 0;
455 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
cf07826e 456
d9c820ee
CB
457 ret = get_st_mode(path, &st_mode);
458 if (ret)
26b717d0 459 return -ENOENT;
cf07826e 460
26b717d0
ZL
461 if (S_ISDIR(st_mode)) {
462 sb->st_mode = st_mode;
71f17cd2
YB
463 sb->st_nlink = 2;
464 return 0;
465 }
cf07826e 466
26b717d0 467 if (S_ISREG(st_mode) || S_ISLNK(st_mode)) {
07e79d35 468 if (strcmp(path, "/sys/devices/system/cpu/online") == 0)
d0aeaf06 469 sb->st_size = sys_devices_system_cpu_online_getsize(path);
07e79d35 470 else
471 sb->st_size = get_sysfile_size(path);
26b717d0 472 sb->st_mode = st_mode;
71f17cd2
YB
473 sb->st_nlink = 1;
474 return 0;
475 }
476
477 return -ENOENT;
478}
479
0d5383b7
CB
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)
26b717d0
ZL
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
0d5383b7
CB
511static 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) {
5aff2eb2
CBM
515 if (dir_filler(filler, buf, ".", 0) != 0 ||
516 dir_filler(filler, buf, "..", 0) != 0 ||
02fa563b 517 dirent_filler(filler, path, "devices", buf, 0) != 0)
0d5383b7
CB
518 return -ENOENT;
519
520 return 0;
521 }
522 if (strcmp(path, "/sys/devices") == 0) {
5aff2eb2
CBM
523 if (dir_filler(filler, buf, ".", 0) != 0 ||
524 dir_filler(filler, buf, "..", 0) != 0 ||
02fa563b 525 dirent_filler(filler, path, "system", buf, 0) != 0)
0d5383b7
CB
526 return -ENOENT;
527
528 return 0;
529 }
530 if (strcmp(path, "/sys/devices/system") == 0) {
5aff2eb2
CBM
531 if (dir_filler(filler, buf, ".", 0) != 0 ||
532 dir_filler(filler, buf, "..", 0) != 0 ||
02fa563b 533 dirent_filler(filler, path, "cpu", buf, 0) != 0)
0d5383b7
CB
534 return -ENOENT;
535
536 return 0;
537 }
538 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
5aff2eb2
CBM
539 if (dir_filler(filler, buf, ".", 0) != 0 ||
540 dir_filler(filler, buf, "..", 0) != 0 ||
02fa563b 541 dirent_filler(filler, path, "online", buf, 0) != 0)
0d5383b7
CB
542 return -ENOENT;
543
544 return 0;
545 }
546
547 return 0;
548}
549
2d7bcab7 550__lxcfs_fuse_ops int sys_readdir(const char *path, void *buf,
0d5383b7
CB
551 fuse_fill_dir_t filler, off_t offset,
552 struct fuse_file_info *fi)
71f17cd2 553{
a6fd03eb 554 __do_closedir DIR *dirp = NULL;
26b717d0
ZL
555 struct dirent *dirent;
556 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
cf07826e 557
26b717d0
ZL
558 if (!liblxcfs_functional())
559 return -EIO;
cf07826e 560
0d5383b7
CB
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
26b717d0 573 switch (f->type) {
a21c4241
CBM
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;
26b717d0 592 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
a21c4241
CBM
593 if (dir_filler(filler, buf, ".", 0) != 0 ||
594 dir_filler(filler, buf, "..", 0) != 0)
76a883b0
CB
595 return -ENOENT;
596
597 return filler_sys_devices_system_cpu(path, buf, filler);
a21c4241
CBM
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;
26b717d0 606 }
a21c4241 607 return 0;
71f17cd2
YB
608 }
609
26b717d0 610 return -EINVAL;
71f17cd2
YB
611}
612
26b717d0
ZL
613__lxcfs_fuse_ops int sys_readlink(const char *path, char *buf, size_t size)
614{
3cf1e562 615 ssize_t ret;
26b717d0
ZL
616
617 if (!liblxcfs_functional())
618 return -EIO;
619
3cf1e562 620 ret = readlink(path, buf, size);
26b717d0
ZL
621 if (ret < 0)
622 return -errno;
3cf1e562
CB
623
624 if ((size_t)ret > size)
26b717d0
ZL
625 return -1;
626
627 buf[ret] = '\0';
628
629 return 0;
630}
0d5383b7
CB
631
632static 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
2d7bcab7 669__lxcfs_fuse_ops int sys_open(const char *path, struct fuse_file_info *fi)
71f17cd2 670{
700dd417 671 __do_free struct file_info *info = NULL;
71f17cd2 672 int type = -1;
71f17cd2 673
26b717d0
ZL
674 if (!liblxcfs_functional())
675 return -EIO;
676
0d5383b7
CB
677 if (!liblxcfs_can_use_sys_cpu())
678 return sys_open_legacy(path, fi);
679
d9c820ee 680 if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
71f17cd2 681 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
d9c820ee
CB
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 }
71f17cd2
YB
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;
700dd417
CB
705
706 info->buf = malloc(info->buflen);
707 if (!info->buf)
708 return -ENOMEM;
709
71f17cd2
YB
710 memset(info->buf, 0, info->buflen);
711 /* set actual size to buffer size */
712 info->size = info->buflen;
713
700dd417 714 fi->fh = PTR_TO_UINT64(move_ptr(info));
71f17cd2
YB
715 return 0;
716}
717
26b717d0 718__lxcfs_fuse_ops int sys_opendir(const char *path, struct fuse_file_info *fi)
71f17cd2 719{
26b717d0
ZL
720 __do_free struct file_info *dir_info = NULL;
721 int type = -1;
cf07826e 722
26b717d0
ZL
723 if (!liblxcfs_functional())
724 return -EIO;
cf07826e 725
d9c820ee 726 if (strcmp(path, "/sys") == 0) {
26b717d0 727 type = LXC_TYPE_SYS;
d9c820ee 728 } else if (strcmp(path, "/sys/devices") == 0) {
26b717d0 729 type = LXC_TYPE_SYS_DEVICES;
d9c820ee 730 } else if (strcmp(path, "/sys/devices/system") == 0) {
26b717d0 731 type = LXC_TYPE_SYS_DEVICES_SYSTEM;
d9c820ee 732 } else if (strcmp(path, "/sys/devices/system/cpu") == 0) {
26b717d0 733 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
d9c820ee
CB
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 }
26b717d0
ZL
746 if (type == -1)
747 return -ENOENT;
cf07826e 748
26b717d0
ZL
749 dir_info = malloc(sizeof(*dir_info));
750 if (!dir_info)
751 return -ENOMEM;
cf07826e 752
26b717d0
ZL
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;
cf07826e 758
26b717d0 759 fi->fh = PTR_TO_UINT64(move_ptr(dir_info));
71f17cd2
YB
760 return 0;
761}
762
0d5383b7
CB
763static 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
26b717d0
ZL
785__lxcfs_fuse_ops int sys_access(const char *path, int mask)
786{
787 if (!liblxcfs_functional())
788 return -EIO;
789
0d5383b7
CB
790 if (!liblxcfs_can_use_sys_cpu())
791 return sys_access_legacy(path, mask);
792
26b717d0
ZL
793 return access(path, mask);
794}
795
0d5383b7
CB
796static int sys_read_legacy(const char *path, char *buf, size_t size,
797 off_t offset, struct fuse_file_info *fi)
71f17cd2 798{
0d5383b7 799 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
71f17cd2 800
0d5383b7
CB
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;
71f17cd2
YB
817}
818
2d7bcab7 819__lxcfs_fuse_ops int sys_read(const char *path, char *buf, size_t size,
0d5383b7 820 off_t offset, struct fuse_file_info *fi)
71f17cd2 821{
99b183fb 822 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
71f17cd2 823
26b717d0
ZL
824 if (!liblxcfs_functional())
825 return -EIO;
826
0d5383b7
CB
827 if (!liblxcfs_can_use_sys_cpu())
828 return sys_read_legacy(path, buf, size, offset, fi);
829
71f17cd2 830 switch (f->type) {
36817cdd 831 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
26b717d0
ZL
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);
71f17cd2 835 }
700dd417
CB
836
837 return -EINVAL;
71f17cd2 838}