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