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