1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #ifndef FUSE_USE_VERSION
8 #define FUSE_USE_VERSION 26
11 #define _FILE_OFFSET_BITS 64
13 #define __STDC_FORMAT_MACROS
30 #include <linux/magic.h>
31 #include <linux/sched.h>
32 #include <sys/epoll.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>
42 #include "memory_utils.h"
43 #include "cgroups/cgroup.h"
45 #include "sysfs_fuse.h"
48 static int sys_devices_system_cpu_online_read(char *buf
, size_t size
,
50 struct fuse_file_info
*fi
)
52 __do_free
char *cg
= NULL
, *cpuset
= NULL
;
53 struct fuse_context
*fc
= fuse_get_context();
54 struct lxcfs_opts
*opts
= (struct lxcfs_opts
*)fc
->private_data
;
55 struct file_info
*d
= INTTYPE_TO_PTR(fi
->fh
);
61 ssize_t total_len
= 0;
72 left
= d
->size
- offset
;
73 total_len
= left
> size
? size
: left
;
74 memcpy(buf
, cache
+ offset
, total_len
);
79 initpid
= lookup_initpid_in_store(fc
->pid
);
80 if (initpid
<= 1 || is_shared_pidns(initpid
))
83 cg
= get_pid_cgroup(initpid
, "cpuset");
85 return read_file_fuse("/sys/devices/system/cpu/online", buf
, size
, d
);
88 cpuset
= get_cpuset(cg
);
92 if (cgroup_ops
->can_use_cpuview(cgroup_ops
) && opts
&& opts
->use_cfs
)
97 max_cpus
= max_cpu_count(cg
);
101 total_len
= snprintf(d
->buf
, d
->buflen
, "0-%d\n", max_cpus
- 1);
103 total_len
= snprintf(d
->buf
, d
->buflen
, "0\n");
105 total_len
= snprintf(d
->buf
, d
->buflen
, "%s\n", cpuset
);
107 if (total_len
< 0 || total_len
>= d
->buflen
)
108 return log_error(0, "Failed to write to cache");
110 d
->size
= (int)total_len
;
113 if (total_len
> size
)
116 memcpy(buf
, d
->buf
, total_len
);
121 static off_t
get_sysfile_size(const char *which
)
123 __do_fclose
FILE *f
= NULL
;
124 __do_free
char *line
= NULL
;
126 ssize_t sz
, answer
= 0;
128 f
= fopen(which
, "re");
132 while ((sz
= getline(&line
, &len
, f
)) != -1)
138 __lxcfs_fuse_ops
int sys_getattr(const char *path
, struct stat
*sb
)
142 memset(sb
, 0, sizeof(struct stat
));
143 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
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;
154 if (strcmp(path
, "/sys/devices") == 0) {
155 sb
->st_mode
= S_IFDIR
| 00555;
160 if (strcmp(path
, "/sys/devices/system") == 0) {
161 sb
->st_mode
= S_IFDIR
| 00555;
166 if (strcmp(path
, "/sys/devices/system/cpu") == 0) {
167 sb
->st_mode
= S_IFDIR
| 00555;
172 if (strcmp(path
, "/sys/devices/system/cpu/online") == 0) {
174 sb
->st_mode
= S_IFREG
| 00444;
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
)
186 if (strcmp(path
, "/sys") == 0) {
187 if (filler(buf
, ".", NULL
, 0) != 0 ||
188 filler(buf
, "..", NULL
, 0) != 0 ||
189 filler(buf
, "devices", NULL
, 0) != 0)
194 if (strcmp(path
, "/sys/devices") == 0) {
195 if (filler(buf
, ".", NULL
, 0) != 0 ||
196 filler(buf
, "..", NULL
, 0) != 0 ||
197 filler(buf
, "system", NULL
, 0) != 0)
202 if (strcmp(path
, "/sys/devices/system") == 0) {
203 if (filler(buf
, ".", NULL
, 0) != 0 ||
204 filler(buf
, "..", NULL
, 0) != 0 ||
205 filler(buf
, "cpu", NULL
, 0) != 0)
210 if (strcmp(path
, "/sys/devices/system/cpu") == 0) {
211 if (filler(buf
, ".", NULL
, 0) != 0 ||
212 filler(buf
, "..", NULL
, 0) != 0 ||
213 filler(buf
, "online", NULL
, 0) != 0)
222 __lxcfs_fuse_ops
int sys_open(const char *path
, struct fuse_file_info
*fi
)
224 __do_free
struct file_info
*info
= NULL
;
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
;
238 info
= malloc(sizeof(*info
));
242 memset(info
, 0, sizeof(*info
));
245 info
->buflen
= get_sysfile_size(path
) + BUF_RESERVE_SIZE
;
247 info
->buf
= malloc(info
->buflen
);
251 memset(info
->buf
, 0, info
->buflen
);
252 /* set actual size to buffer size */
253 info
->size
= info
->buflen
;
255 fi
->fh
= PTR_TO_UINT64(move_ptr(info
));
259 __lxcfs_fuse_ops
int sys_access(const char *path
, int mask
)
261 if (strcmp(path
, "/sys") == 0 && access(path
, R_OK
) == 0)
264 if (strcmp(path
, "/sys/devices") == 0 && access(path
, R_OK
) == 0)
267 if (strcmp(path
, "/sys/devices/system") == 0 && access(path
, R_OK
) == 0)
270 if (strcmp(path
, "/sys/devices/system/cpu") == 0 &&
271 access(path
, R_OK
) == 0)
274 /* these are all read-only */
275 if ((mask
& ~R_OK
) != 0)
281 __lxcfs_fuse_ops
int sys_release(const char *path
, struct fuse_file_info
*fi
)
283 do_release_file_info(fi
);
287 __lxcfs_fuse_ops
int sys_releasedir(const char *path
, struct fuse_file_info
*fi
)
289 do_release_file_info(fi
);
293 __lxcfs_fuse_ops
int sys_read(const char *path
, char *buf
, size_t size
,
294 off_t offset
, struct fuse_file_info
*fi
)
296 struct file_info
*f
= INTTYPE_TO_PTR(fi
->fh
);
299 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE
:
300 if (liblxcfs_functional())
301 return sys_devices_system_cpu_online_read(buf
, size
, offset
, fi
);
303 return read_file_fuse_with_offset(LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH
,
304 buf
, size
, offset
, f
);
305 case LXC_TYPE_SYS_DEVICES
:
307 case LXC_TYPE_SYS_DEVICES_SYSTEM
:
309 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU
: