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 return read_file_fuse("/sys/devices/system/cpu/online", buf
, size
, d
);
109 if (total_len
< 0 || total_len
>= d
->buflen
)
110 return log_error(0, "Failed to write to cache");
112 d
->size
= (int)total_len
;
115 if (total_len
> size
)
118 memcpy(buf
, d
->buf
, total_len
);
123 static off_t
get_sysfile_size(const char *which
)
125 __do_fclose
FILE *f
= NULL
;
126 __do_free
char *line
= NULL
;
128 ssize_t sz
, answer
= 0;
130 f
= fopen(which
, "re");
134 while ((sz
= getline(&line
, &len
, f
)) != -1)
140 __lxcfs_fuse_ops
int sys_getattr(const char *path
, struct stat
*sb
)
144 memset(sb
, 0, sizeof(struct stat
));
145 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
148 sb
->st_uid
= sb
->st_gid
= 0;
149 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
150 if (strcmp(path
, "/sys") == 0) {
151 sb
->st_mode
= S_IFDIR
| 00555;
156 if (strcmp(path
, "/sys/devices") == 0) {
157 sb
->st_mode
= S_IFDIR
| 00555;
162 if (strcmp(path
, "/sys/devices/system") == 0) {
163 sb
->st_mode
= S_IFDIR
| 00555;
168 if (strcmp(path
, "/sys/devices/system/cpu") == 0) {
169 sb
->st_mode
= S_IFDIR
| 00555;
174 if (strcmp(path
, "/sys/devices/system/cpu/online") == 0) {
176 sb
->st_mode
= S_IFREG
| 00444;
184 __lxcfs_fuse_ops
int sys_readdir(const char *path
, void *buf
,
185 fuse_fill_dir_t filler
, off_t offset
,
186 struct fuse_file_info
*fi
)
188 if (strcmp(path
, "/sys") == 0) {
189 if (filler(buf
, ".", NULL
, 0) != 0 ||
190 filler(buf
, "..", NULL
, 0) != 0 ||
191 filler(buf
, "devices", NULL
, 0) != 0)
196 if (strcmp(path
, "/sys/devices") == 0) {
197 if (filler(buf
, ".", NULL
, 0) != 0 ||
198 filler(buf
, "..", NULL
, 0) != 0 ||
199 filler(buf
, "system", NULL
, 0) != 0)
204 if (strcmp(path
, "/sys/devices/system") == 0) {
205 if (filler(buf
, ".", NULL
, 0) != 0 ||
206 filler(buf
, "..", NULL
, 0) != 0 ||
207 filler(buf
, "cpu", NULL
, 0) != 0)
212 if (strcmp(path
, "/sys/devices/system/cpu") == 0) {
213 if (filler(buf
, ".", NULL
, 0) != 0 ||
214 filler(buf
, "..", NULL
, 0) != 0 ||
215 filler(buf
, "online", NULL
, 0) != 0)
224 __lxcfs_fuse_ops
int sys_open(const char *path
, struct fuse_file_info
*fi
)
226 __do_free
struct file_info
*info
= NULL
;
229 if (strcmp(path
, "/sys/devices") == 0)
230 type
= LXC_TYPE_SYS_DEVICES
;
231 if (strcmp(path
, "/sys/devices/system") == 0)
232 type
= LXC_TYPE_SYS_DEVICES_SYSTEM
;
233 if (strcmp(path
, "/sys/devices/system/cpu") == 0)
234 type
= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU
;
235 if (strcmp(path
, "/sys/devices/system/cpu/online") == 0)
236 type
= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE
;
240 info
= malloc(sizeof(*info
));
244 memset(info
, 0, sizeof(*info
));
247 info
->buflen
= get_sysfile_size(path
) + BUF_RESERVE_SIZE
;
249 info
->buf
= malloc(info
->buflen
);
253 memset(info
->buf
, 0, info
->buflen
);
254 /* set actual size to buffer size */
255 info
->size
= info
->buflen
;
257 fi
->fh
= PTR_TO_UINT64(move_ptr(info
));
261 __lxcfs_fuse_ops
int sys_access(const char *path
, int mask
)
263 if (strcmp(path
, "/sys") == 0 && access(path
, R_OK
) == 0)
266 if (strcmp(path
, "/sys/devices") == 0 && access(path
, R_OK
) == 0)
269 if (strcmp(path
, "/sys/devices/system") == 0 && access(path
, R_OK
) == 0)
272 if (strcmp(path
, "/sys/devices/system/cpu") == 0 &&
273 access(path
, R_OK
) == 0)
276 /* these are all read-only */
277 if ((mask
& ~R_OK
) != 0)
283 __lxcfs_fuse_ops
int sys_release(const char *path
, struct fuse_file_info
*fi
)
285 do_release_file_info(fi
);
289 __lxcfs_fuse_ops
int sys_releasedir(const char *path
, struct fuse_file_info
*fi
)
291 do_release_file_info(fi
);
295 __lxcfs_fuse_ops
int sys_read(const char *path
, char *buf
, size_t size
,
296 off_t offset
, struct fuse_file_info
*fi
)
298 struct file_info
*f
= INTTYPE_TO_PTR(fi
->fh
);
301 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE
:
302 if (liblxcfs_functional())
303 return sys_devices_system_cpu_online_read(buf
, size
, offset
, fi
);
305 return read_file_fuse_with_offset(LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH
,
306 buf
, size
, offset
, f
);
307 case LXC_TYPE_SYS_DEVICES
:
309 case LXC_TYPE_SYS_DEVICES_SYSTEM
:
311 case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU
: