1 /* SPDX-License-Identifier: LGPL-2.1+ */
10 #ifndef FUSE_USE_VERSION
11 #define FUSE_USE_VERSION 30
14 #ifndef FUSE_USE_VERSION
15 #define FUSE_USE_VERSION 26
19 #define _FILE_OFFSET_BITS 64
21 #define __STDC_FORMAT_MACROS
38 #include <linux/magic.h>
39 #include <linux/sched.h>
40 #include <sys/epoll.h>
42 #include <sys/mount.h>
43 #include <sys/param.h>
44 #include <sys/socket.h>
45 #include <sys/syscall.h>
46 #include <sys/sysinfo.h>
50 #include "memory_utils.h"
51 #include "cgroups/cgroup.h"
52 #include "fuse_compat.h"
53 #include "sysfs_fuse.h"
56 static int sys_devices_system_cpu_online_read(char *buf
, size_t size
,
58 struct fuse_file_info
*fi
)
60 __do_free
char *cg
= NULL
, *cpuset
= NULL
;
61 struct fuse_context
*fc
= fuse_get_context();
62 struct lxcfs_opts
*opts
= (struct lxcfs_opts
*)fc
->private_data
;
63 struct file_info
*d
= INTTYPE_TO_PTR(fi
->fh
);
69 ssize_t total_len
= 0;
80 left
= d
->size
- offset
;
81 total_len
= left
> size
? size
: left
;
82 memcpy(buf
, cache
+ offset
, total_len
);
87 initpid
= lookup_initpid_in_store(fc
->pid
);
88 if (initpid
<= 1 || is_shared_pidns(initpid
))
91 cg
= get_pid_cgroup(initpid
, "cpuset");
93 return read_file_fuse("/sys/devices/system/cpu/online", buf
, size
, d
);
96 cpuset
= get_cpuset(cg
);
100 if (cgroup_ops
->can_use_cpuview(cgroup_ops
) && opts
&& opts
->use_cfs
)
105 max_cpus
= max_cpu_count(cg
);
109 total_len
= snprintf(d
->buf
, d
->buflen
, "0-%d\n", max_cpus
- 1);
111 total_len
= snprintf(d
->buf
, d
->buflen
, "0\n");
113 total_len
= snprintf(d
->buf
, d
->buflen
, "%s\n", cpuset
);
115 if (total_len
< 0 || total_len
>= d
->buflen
)
116 return log_error(0, "Failed to write to cache");
118 d
->size
= (int)total_len
;
121 if (total_len
> size
)
124 memcpy(buf
, d
->buf
, total_len
);
129 static off_t
get_sysfile_size(const char *which
)
131 __do_fclose
FILE *f
= NULL
;
132 __do_free
char *line
= NULL
;
134 ssize_t sz
, answer
= 0;
136 f
= fopen(which
, "re");
140 while ((sz
= getline(&line
, &len
, f
)) != -1)
146 __lxcfs_fuse_ops
int sys_getattr(const char *path
, struct stat
*sb
)
150 memset(sb
, 0, sizeof(struct stat
));
151 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
154 sb
->st_uid
= sb
->st_gid
= 0;
155 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
156 if (strcmp(path
, "/sys") == 0) {
157 sb
->st_mode
= S_IFDIR
| 00555;
162 if (strcmp(path
, "/sys/devices") == 0) {
163 sb
->st_mode
= S_IFDIR
| 00555;
168 if (strcmp(path
, "/sys/devices/system") == 0) {
169 sb
->st_mode
= S_IFDIR
| 00555;
174 if (strcmp(path
, "/sys/devices/system/cpu") == 0) {
175 sb
->st_mode
= S_IFDIR
| 00555;
180 if (strcmp(path
, "/sys/devices/system/cpu/online") == 0) {
182 sb
->st_mode
= S_IFREG
| 00444;
190 __lxcfs_fuse_ops
int sys_readdir(const char *path
, void *buf
,
191 fuse_fill_dir_t filler
, off_t offset
,
192 struct fuse_file_info
*fi
)
194 if (strcmp(path
, "/sys") == 0) {
195 if (DIR_FILLER(filler
, buf
, ".", NULL
, 0) != 0 ||
196 DIR_FILLER(filler
, buf
, "..", NULL
, 0) != 0 ||
197 DIR_FILLER(filler
, buf
, "devices", NULL
, 0) != 0)
202 if (strcmp(path
, "/sys/devices") == 0) {
203 if (DIR_FILLER(filler
, buf
, ".", NULL
, 0) != 0 ||
204 DIR_FILLER(filler
, buf
, "..", NULL
, 0) != 0 ||
205 DIR_FILLER(filler
, buf
, "system", NULL
, 0) != 0)
210 if (strcmp(path
, "/sys/devices/system") == 0) {
211 if (DIR_FILLER(filler
, buf
, ".", NULL
, 0) != 0 ||
212 DIR_FILLER(filler
, buf
, "..", NULL
, 0) != 0 ||
213 DIR_FILLER(filler
, buf
, "cpu", NULL
, 0) != 0)
218 if (strcmp(path
, "/sys/devices/system/cpu") == 0) {
219 if (DIR_FILLER(filler
, buf
, ".", NULL
, 0) != 0 ||
220 DIR_FILLER(filler
, buf
, "..", NULL
, 0) != 0 ||
221 DIR_FILLER(filler
, buf
, "online", NULL
, 0) != 0)
230 __lxcfs_fuse_ops
int sys_open(const char *path
, struct fuse_file_info
*fi
)
232 __do_free
struct file_info
*info
= NULL
;
235 if (strcmp(path
, "/sys/devices") == 0)
236 type
= LXC_TYPE_SYS_DEVICES
;
237 if (strcmp(path
, "/sys/devices/system") == 0)
238 type
= LXC_TYPE_SYS_DEVICES_SYSTEM
;
239 if (strcmp(path
, "/sys/devices/system/cpu") == 0)
240 type
= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU
;
241 if (strcmp(path
, "/sys/devices/system/cpu/online") == 0)
242 type
= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE
;
246 info
= malloc(sizeof(*info
));
250 memset(info
, 0, sizeof(*info
));
253 info
->buflen
= get_sysfile_size(path
) + BUF_RESERVE_SIZE
;
255 info
->buf
= malloc(info
->buflen
);
259 memset(info
->buf
, 0, info
->buflen
);
260 /* set actual size to buffer size */
261 info
->size
= info
->buflen
;
263 fi
->fh
= PTR_TO_UINT64(move_ptr(info
));
267 __lxcfs_fuse_ops
int sys_access(const char *path
, int mask
)
269 if (strcmp(path
, "/sys") == 0 && access(path
, R_OK
) == 0)
272 if (strcmp(path
, "/sys/devices") == 0 && access(path
, R_OK
) == 0)
275 if (strcmp(path
, "/sys/devices/system") == 0 && access(path
, R_OK
) == 0)
278 if (strcmp(path
, "/sys/devices/system/cpu") == 0 &&
279 access(path
, R_OK
) == 0)
282 /* these are all read-only */
283 if ((mask
& ~R_OK
) != 0)
289 __lxcfs_fuse_ops
int sys_release(const char *path
, struct fuse_file_info
*fi
)
291 do_release_file_info(fi
);
295 __lxcfs_fuse_ops
int sys_releasedir(const char *path
, struct fuse_file_info
*fi
)
297 do_release_file_info(fi
);
301 __lxcfs_fuse_ops
int sys_read(const char *path
, char *buf
, size_t size
,
302 off_t offset
, struct fuse_file_info
*fi
)
304 struct file_info
*f
= INTTYPE_TO_PTR(fi
->fh
);
307 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE
:
308 if (liblxcfs_functional())
309 return sys_devices_system_cpu_online_read(buf
, size
, offset
, fi
);
311 return read_file_fuse_with_offset(LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH
,
312 buf
, size
, offset
, f
);
313 case LXC_TYPE_SYS_DEVICES
:
315 case LXC_TYPE_SYS_DEVICES_SYSTEM
:
317 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU
: