]> git.proxmox.com Git - mirror_lxcfs.git/blob - src/sysfs_fuse.c
tree-wide: align lxcfs and lxc licensing
[mirror_lxcfs.git] / src / sysfs_fuse.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #endif
6
7 #ifndef FUSE_USE_VERSION
8 #define FUSE_USE_VERSION 26
9 #endif
10
11 #define _FILE_OFFSET_BITS 64
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"
42 #include "memory_utils.h"
43 #include "cgroups/cgroup.h"
44 #include "config.h"
45 #include "sysfs_fuse.h"
46 #include "utils.h"
47
48 static int sys_devices_system_cpu_online_read(char *buf, size_t size,
49 off_t offset,
50 struct fuse_file_info *fi)
51 {
52 __do_free char *cg = NULL, *cpuset = NULL;
53 struct fuse_context *fc = fuse_get_context();
54 struct file_info *d = INTTYPE_TO_PTR(fi->fh);
55 char *cache = d->buf;
56 bool use_view;
57
58 int max_cpus = 0;
59 pid_t initpid;
60 ssize_t total_len = 0;
61
62 if (offset) {
63 int left;
64
65 if (!d->cached)
66 return 0;
67
68 if (offset > d->size)
69 return -EINVAL;
70
71 left = d->size - offset;
72 total_len = left > size ? size : left;
73 memcpy(buf, cache + offset, total_len);
74
75 return total_len;
76 }
77
78 initpid = lookup_initpid_in_store(fc->pid);
79 if (initpid <= 1 || is_shared_pidns(initpid))
80 initpid = fc->pid;
81
82 cg = get_pid_cgroup(initpid, "cpuset");
83 if (!cg)
84 return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d);
85 prune_init_slice(cg);
86
87 cpuset = get_cpuset(cg);
88 if (!cpuset)
89 return 0;
90
91 use_view = cgroup_ops->can_use_cpuview(cgroup_ops);
92 if (use_view)
93 max_cpus = max_cpu_count(cg);
94
95 if (max_cpus == 0)
96 return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d);
97 if (max_cpus > 1)
98 total_len = snprintf(d->buf, d->buflen, "0-%d\n", max_cpus - 1);
99 else
100 total_len = snprintf(d->buf, d->buflen, "0\n");
101 if (total_len < 0 || total_len >= d->buflen) {
102 lxcfs_error("%s\n", "failed to write to cache");
103 return 0;
104 }
105
106 d->size = (int)total_len;
107 d->cached = 1;
108
109 if (total_len > size)
110 total_len = size;
111
112 memcpy(buf, d->buf, total_len);
113
114 return total_len;
115 }
116
117 static off_t get_sysfile_size(const char *which)
118 {
119 __do_fclose FILE *f = NULL;
120 __do_free char *line = NULL;
121 size_t len = 0;
122 ssize_t sz, answer = 0;
123
124 f = fopen(which, "re");
125 if (!f)
126 return 0;
127
128 while ((sz = getline(&line, &len, f)) != -1)
129 answer += sz;
130
131 return answer;
132 }
133
134 int sys_getattr(const char *path, struct stat *sb)
135 {
136 struct timespec now;
137
138 memset(sb, 0, sizeof(struct stat));
139 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
140 return -EINVAL;
141 sb->st_uid = sb->st_gid = 0;
142 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
143 if (strcmp(path, "/sys") == 0) {
144 sb->st_mode = S_IFDIR | 00555;
145 sb->st_nlink = 2;
146 return 0;
147 }
148 if (strcmp(path, "/sys/devices") == 0) {
149 sb->st_mode = S_IFDIR | 00555;
150 sb->st_nlink = 2;
151 return 0;
152 }
153 if (strcmp(path, "/sys/devices/system") == 0) {
154 sb->st_mode = S_IFDIR | 00555;
155 sb->st_nlink = 2;
156 return 0;
157 }
158 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
159 sb->st_mode = S_IFDIR | 00555;
160 sb->st_nlink = 2;
161 return 0;
162 }
163 if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
164 sb->st_size = 0;
165 sb->st_mode = S_IFREG | 00444;
166 sb->st_nlink = 1;
167 return 0;
168 }
169
170 return -ENOENT;
171 }
172
173 int sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
174 off_t offset, struct fuse_file_info *fi)
175 {
176 if (strcmp(path, "/sys") == 0) {
177 if (filler(buf, ".", NULL, 0) != 0 ||
178 filler(buf, "..", NULL, 0) != 0 ||
179 filler(buf, "devices", NULL, 0) != 0)
180 return -ENOENT;
181 return 0;
182 }
183 if (strcmp(path, "/sys/devices") == 0) {
184 if (filler(buf, ".", NULL, 0) != 0 ||
185 filler(buf, "..", NULL, 0) != 0 ||
186 filler(buf, "system", NULL, 0) != 0)
187 return -ENOENT;
188 return 0;
189 }
190 if (strcmp(path, "/sys/devices/system") == 0) {
191 if (filler(buf, ".", NULL, 0) != 0 ||
192 filler(buf, "..", NULL, 0) != 0 ||
193 filler(buf, "cpu", NULL, 0) != 0)
194 return -ENOENT;
195 return 0;
196 }
197 if (strcmp(path, "/sys/devices/system/cpu") == 0) {
198 if (filler(buf, ".", NULL, 0) != 0 ||
199 filler(buf, "..", NULL, 0) != 0 ||
200 filler(buf, "online", NULL, 0) != 0)
201 return -ENOENT;
202 return 0;
203 }
204
205 return 0;
206 }
207
208 int sys_open(const char *path, struct fuse_file_info *fi)
209 {
210 __do_free struct file_info *info = NULL;
211 int type = -1;
212
213 if (strcmp(path, "/sys/devices") == 0)
214 type = LXC_TYPE_SYS_DEVICES;
215 if (strcmp(path, "/sys/devices/system") == 0)
216 type = LXC_TYPE_SYS_DEVICES_SYSTEM;
217 if (strcmp(path, "/sys/devices/system/cpu") == 0)
218 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
219 if (strcmp(path, "/sys/devices/system/cpu/online") == 0)
220 type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
221 if (type == -1)
222 return -ENOENT;
223
224 info = malloc(sizeof(*info));
225 if (!info)
226 return -ENOMEM;
227
228 memset(info, 0, sizeof(*info));
229 info->type = type;
230
231 info->buflen = get_sysfile_size(path) + BUF_RESERVE_SIZE;
232
233 info->buf = malloc(info->buflen);
234 if (!info->buf)
235 return -ENOMEM;
236
237 memset(info->buf, 0, info->buflen);
238 /* set actual size to buffer size */
239 info->size = info->buflen;
240
241 fi->fh = PTR_TO_UINT64(move_ptr(info));
242 return 0;
243 }
244
245 int sys_access(const char *path, int mask)
246 {
247 if (strcmp(path, "/sys") == 0 && access(path, R_OK) == 0)
248 return 0;
249 if (strcmp(path, "/sys/devices") == 0 && access(path, R_OK) == 0)
250 return 0;
251 if (strcmp(path, "/sys/devices/system") == 0 && access(path, R_OK) == 0)
252 return 0;
253 if (strcmp(path, "/sys/devices/system/cpu") == 0 &&
254 access(path, R_OK) == 0)
255 return 0;
256 /* these are all read-only */
257 if ((mask & ~R_OK) != 0)
258 return -EACCES;
259 return 0;
260 }
261
262 int sys_release(const char *path, struct fuse_file_info *fi)
263 {
264 do_release_file_info(fi);
265 return 0;
266 }
267
268 int sys_releasedir(const char *path, struct fuse_file_info *fi)
269 {
270 do_release_file_info(fi);
271 return 0;
272 }
273
274 int sys_read(const char *path, char *buf, size_t size, off_t offset,
275 struct fuse_file_info *fi)
276 {
277 struct file_info *f = INTTYPE_TO_PTR(fi->fh);
278
279 switch (f->type) {
280 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
281 return sys_devices_system_cpu_online_read(buf, size, offset, fi);
282 case LXC_TYPE_SYS_DEVICES:
283 break;
284 case LXC_TYPE_SYS_DEVICES_SYSTEM:
285 break;
286 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
287 break;
288 }
289
290 return -EINVAL;
291 }