1 /* SPDX-License-Identifier: LGPL-2.1+ */
22 #include <linux/sched.h>
23 #include <sys/epoll.h>
24 #include <sys/mount.h>
25 #include <sys/socket.h>
26 #include <linux/limits.h>
28 #include "lxcfs_fuse.h"
31 #include "lxcfs_fuse_compat.h"
33 #include "memory_utils.h"
37 /* Functions to keep track of number of threads using the library */
39 static int users_count
;
40 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
41 static void lock_mutex(pthread_mutex_t
*l
)
45 ret
= pthread_mutex_lock(l
);
47 log_exit("%s - returned: %d\n", strerror(ret
), ret
);
50 static void unlock_mutex(pthread_mutex_t
*l
)
54 ret
= pthread_mutex_unlock(l
);
56 log_exit("%s - returned: %d\n", strerror(ret
), ret
);
59 static inline void users_lock(void)
61 lock_mutex(&user_count_mutex
);
64 static inline void users_unlock(void)
66 unlock_mutex(&user_count_mutex
);
69 /* Returns file info type of custom type declaration carried
70 * in fuse_file_info */
71 static inline enum lxcfs_virt_t
file_info_type(struct fuse_file_info
*fi
)
75 f
= INTTYPE_TO_PTR(fi
->fh
);
79 if (!LXCFS_TYPE_OK(f
->type
))
85 static pthread_t loadavg_pid
= 0;
87 /* Returns zero on success */
88 static int start_loadavg(void)
91 pthread_t (*__load_daemon
)(int);
94 __load_daemon
= (pthread_t(*)(int))dlsym(dlopen_handle
, "load_daemon");
97 return log_error(-1, "%s - Failed to start loadavg daemon", error
);
99 loadavg_pid
= __load_daemon(1);
106 /* Returns zero on success */
107 static int stop_loadavg(void)
110 int (*__stop_load_daemon
)(pthread_t
);
112 __stop_load_daemon
= (int (*)(pthread_t
))dlsym(dlopen_handle
, "stop_load_daemon");
115 return log_error(-1, "%s - Failed to stop loadavg daemon", error
);
117 if (__stop_load_daemon(loadavg_pid
))
123 static volatile sig_atomic_t need_reload
;
125 static int lxcfs_init_library(void)
128 void *(*__lxcfs_fuse_init
)(struct fuse_conn_info
* conn
, void * cfg
);
131 __lxcfs_fuse_init
= (void *(*)(struct fuse_conn_info
* conn
, void * cfg
))dlsym(dlopen_handle
, "lxcfs_fuse_init");
134 return log_error(-1, "%s - Failed to find lxcfs_fuse_init()", error
);
136 __lxcfs_fuse_init(NULL
, NULL
);
141 /* do_reload - reload the dynamic library. Done under
142 * lock and when we know the user_count was 0 */
143 static void do_reload(bool reinit
)
146 char lxcfs_lib_path
[PATH_MAX
];
152 lxcfs_info("Closed liblxcfs.so");
153 dlclose(dlopen_handle
);
156 /* First try loading using ld.so */
158 dlopen_handle
= dlopen("liblxcfs.so", RTLD_NOW
);
160 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
163 lxcfs_debug("Opened liblxcfs.so");
168 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
169 ret
= snprintf(lxcfs_lib_path
, sizeof(lxcfs_lib_path
), "%s/lxcfs/liblxcfs.so", LIBDIR
);
171 ret
= snprintf(lxcfs_lib_path
, sizeof(lxcfs_lib_path
), "/usr/local/lib/lxcfs/liblxcfs.so");
173 if (ret
< 0 || (size_t)ret
>= sizeof(lxcfs_lib_path
))
174 log_exit("Failed to create path to open liblxcfs");
176 dlopen_handle
= dlopen(lxcfs_lib_path
, RTLD_LAZY
);
178 log_exit("%s - Failed to open liblxcfs.so", dlerror());
180 lxcfs_debug("Opened %s", lxcfs_lib_path
);
183 /* initialize the library */
184 if (reinit
&& lxcfs_init_library() < 0) {
185 log_exit("Failed to initialize liblxcfs.so");
192 lxcfs_info("Reloaded LXCFS");
196 static void up_users(void)
199 if (users_count
== 0 && need_reload
)
205 static void down_users(void)
212 static void sigusr1_reload(int signo
, siginfo_t
*info
, void *extra
)
217 /* Functions to run the library methods */
218 static int do_cg_getattr(const char *path
, struct stat
*sb
)
221 int (*__cg_getattr
)(const char *path
, struct stat
*sb
);
224 __cg_getattr
= (int (*)(const char *, struct stat
*))dlsym(dlopen_handle
, "cg_getattr");
227 return log_error(-1, "%s - Failed to find cg_getattr()", error
);
229 return __cg_getattr(path
, sb
);
232 static int do_proc_getattr(const char *path
, struct stat
*sb
)
235 int (*__proc_getattr
)(const char *path
, struct stat
*sb
);
238 __proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
241 return log_error(-1, "%s - Failed to find proc_getattr()", error
);
243 return __proc_getattr(path
, sb
);
246 static int do_sys_getattr(const char *path
, struct stat
*sb
)
249 int (*__sys_getattr
)(const char *path
, struct stat
*sb
);
252 __sys_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "sys_getattr");
255 return log_error(-1, "%s - Failed to find sys_getattr()", error
);
257 return __sys_getattr(path
, sb
);
260 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
261 struct fuse_file_info
*fi
)
264 int (*__cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
265 struct fuse_file_info
*fi
);
268 __cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_read");
271 return log_error(-1, "%s - Failed to find cg_read()", error
);
273 return __cg_read(path
, buf
, size
, offset
, fi
);
276 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
277 struct fuse_file_info
*fi
)
280 int (*__proc_read
)(const char *path
, char *buf
, size_t size
,
281 off_t offset
, struct fuse_file_info
*fi
);
284 __proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "proc_read");
287 return log_error(-1, "%s - Failed to find proc_read()", error
);
289 return __proc_read(path
, buf
, size
, offset
, fi
);
292 static int do_sys_read(const char *path
, char *buf
, size_t size
, off_t offset
,
293 struct fuse_file_info
*fi
)
296 int (*__sys_read
)(const char *path
, char *buf
, size_t size
,
297 off_t offset
, struct fuse_file_info
*fi
);
300 __sys_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_read");
303 return log_error(-1, "%s - Failed to find sys_read()", error
);
305 return __sys_read(path
, buf
, size
, offset
, fi
);
308 static int do_cg_write(const char *path
, const char *buf
, size_t size
,
309 off_t offset
, struct fuse_file_info
*fi
)
312 int (*__cg_write
)(const char *path
, const char *buf
, size_t size
,
313 off_t offset
, struct fuse_file_info
*fi
);
316 __cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_write");
319 return log_error(-1, "%s - Failed to find cg_write()", error
);
321 return __cg_write(path
, buf
, size
, offset
, fi
);
324 static int do_sys_write(const char *path
, const char *buf
, size_t size
,
325 off_t offset
, struct fuse_file_info
*fi
)
328 int (*__sys_write
)(const char *path
, const char *buf
, size_t size
,
329 off_t offset
, struct fuse_file_info
*fi
);
332 __sys_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_write");
335 return log_error(-1, "%s - Failed to find sys_write()", error
);
337 return __sys_write(path
, buf
, size
, offset
, fi
);
340 static int do_cg_mkdir(const char *path
, mode_t mode
)
343 int (*__cg_mkdir
)(const char *path
, mode_t mode
);
346 __cg_mkdir
= (int (*)(const char *, mode_t
))dlsym(dlopen_handle
, "cg_mkdir");
349 return log_error(-1, "%s - Failed to find cg_mkdir()", error
);
351 return __cg_mkdir(path
, mode
);
354 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
357 int (*__cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
360 __cg_chown
= (int (*)(const char *, uid_t
, gid_t
))dlsym(dlopen_handle
, "cg_chown");
363 return log_error(-1, "%s - Failed to find cg_chown()", error
);
365 return __cg_chown(path
, uid
, gid
);
368 static int do_cg_rmdir(const char *path
)
371 int (*__cg_rmdir
)(const char *path
);
374 __cg_rmdir
= (int (*)(const char *path
))dlsym(dlopen_handle
, "cg_rmdir");
377 return log_error(-1, "%s - Failed to find cg_rmdir()", error
);
379 return __cg_rmdir(path
);
382 static int do_cg_chmod(const char *path
, mode_t mode
)
385 int (*__cg_chmod
)(const char *path
, mode_t mode
);
388 __cg_chmod
= (int (*)(const char *, mode_t
))dlsym(dlopen_handle
, "cg_chmod");
391 return log_error(-1, "%s - Failed to find cg_chmod()", error
);
393 return __cg_chmod(path
, mode
);
396 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
397 off_t offset
, struct fuse_file_info
*fi
)
400 int (*__cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
401 off_t offset
, struct fuse_file_info
*fi
);
404 __cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_readdir");
407 return log_error(-1, "%s - Failed to find cg_readdir()", error
);
409 return __cg_readdir(path
, buf
, filler
, offset
, fi
);
412 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
413 off_t offset
, struct fuse_file_info
*fi
)
416 int (*__proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
417 off_t offset
, struct fuse_file_info
*fi
);
420 __proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "proc_readdir");
423 return log_error(-1, "%s - Failed to find proc_readdir()", error
);
425 return __proc_readdir(path
, buf
, filler
, offset
, fi
);
428 static int do_sys_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
429 off_t offset
, struct fuse_file_info
*fi
)
432 int (*__sys_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
433 off_t offset
, struct fuse_file_info
*fi
);
436 __sys_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_readdir");
439 return log_error(-1, "%s - Failed to find sys_readdir()", error
);
441 return __sys_readdir(path
, buf
, filler
, offset
, fi
);
444 static int do_sys_readlink(const char *path
, char *buf
, size_t size
)
447 int (*__sys_readlink
)(const char *path
, char *buf
, size_t size
);
450 __sys_readlink
= (int (*)(const char *, char *, size_t))dlsym(dlopen_handle
, "sys_readlink");
453 return log_error(-1, "%s - Failed to find sys_readlink()", error
);
455 return __sys_readlink(path
, buf
, size
);
458 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
461 int (*__cg_open
)(const char *path
, struct fuse_file_info
*fi
);
464 __cg_open
= (int (*)(const char *, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_open");
467 return log_error(-1, "%s - Failed to find cg_open()", error
);
469 return __cg_open(path
, fi
);
472 static int do_cg_access(const char *path
, int mode
)
475 int (*__cg_access
)(const char *path
, int mode
);
478 __cg_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "cg_access");
481 return log_error(-1, "%s - Failed to find cg_access()", error
);
483 return __cg_access(path
, mode
);
486 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
489 int (*__proc_open
)(const char *path
, struct fuse_file_info
*fi
);
492 __proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "proc_open");
495 return log_error(-1, "%s - Failed to find proc_open()", error
);
497 return __proc_open(path
, fi
);
500 static int do_proc_access(const char *path
, int mode
)
503 int (*__proc_access
)(const char *path
, int mode
);
506 __proc_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "proc_access");
509 return log_error(-1, "%s - Failed to find proc_access()", error
);
511 return __proc_access(path
, mode
);
514 static int do_sys_open(const char *path
, struct fuse_file_info
*fi
)
517 int (*__sys_open
)(const char *path
, struct fuse_file_info
*fi
);
520 __sys_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "sys_open");
523 return log_error(-1, "%s - Failed to find sys_open()", error
);
525 return __sys_open(path
, fi
);
528 static int do_sys_opendir(const char *path
, struct fuse_file_info
*fi
)
531 int (*__sys_opendir
)(const char *path
, struct fuse_file_info
*fi
);
534 __sys_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "sys_opendir");
537 return log_error(-1, "%s - Failed to find sys_opendir()", error
);
539 return __sys_opendir(path
, fi
);
542 static int do_sys_access(const char *path
, int mode
)
545 int (*__sys_access
)(const char *path
, int mode
);
548 __sys_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "sys_access");
551 return log_error(-1, "%s - Failed to find sys_access()", error
);
553 return __sys_access(path
, mode
);
556 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
559 int (*__cg_release
)(const char *path
, struct fuse_file_info
*fi
);
562 __cg_release
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_release");
565 return log_error(-1, "%s - Failed to find cg_release()", error
);
567 return __cg_release(path
, fi
);
570 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
573 int (*__proc_release
)(const char *path
, struct fuse_file_info
*fi
);
576 __proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
579 return log_error(-1, "%s - Failed to find proc_release()", error
);
581 return __proc_release(path
, fi
);
584 static int do_sys_release(const char *path
, struct fuse_file_info
*fi
)
587 int (*__sys_release
)(const char *path
, struct fuse_file_info
*fi
);
590 __sys_release
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_release");
593 return log_error(-1, "%s - Failed to find sys_release()", error
);
595 return __sys_release(path
, fi
);
598 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
601 int (*__cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
604 __cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "cg_opendir");
607 return log_error(-1, "%s - Failed to find cg_opendir()", error
);
609 return __cg_opendir(path
, fi
);
612 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
615 int (*__cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
618 __cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_releasedir");
621 return log_error(-1, "%s - Failed to find cg_releasedir()", error
);
623 return __cg_releasedir(path
, fi
);
626 static int do_sys_releasedir(const char *path
, struct fuse_file_info
*fi
)
629 int (*__sys_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
632 __sys_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_releasedir");
635 return log_error(-1, "%s - Failed to find sys_releasedir()", error
);
637 return __sys_releasedir(path
, fi
);
641 static int lxcfs_getattr(const char *path
, struct stat
*sb
, struct fuse_file_info
*fi
)
643 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
649 if (strcmp(path
, "/") == 0) {
650 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
652 sb
->st_uid
= sb
->st_gid
= 0;
653 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
655 sb
->st_mode
= S_IFDIR
| 00755;
660 if (strncmp(path
, "/cgroup", 7) == 0) {
662 ret
= do_cg_getattr(path
, sb
);
667 if (strncmp(path
, "/proc", 5) == 0) {
669 ret
= do_proc_getattr(path
, sb
);
674 if (strncmp(path
, "/sys", 4) == 0) {
676 ret
= do_sys_getattr(path
, sb
);
684 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
688 if (strcmp(path
, "/") == 0)
691 if (strncmp(path
, "/cgroup", 7) == 0) {
693 ret
= do_cg_opendir(path
, fi
);
698 if (strcmp(path
, "/proc") == 0)
701 if (strncmp(path
, "/sys", 4) == 0) {
703 ret
= do_sys_opendir(path
, fi
);
712 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
713 off_t offset
, struct fuse_file_info
*fi
, enum fuse_readdir_flags flags
)
715 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
716 off_t offset
, struct fuse_file_info
*fi
)
721 if (strcmp(path
, "/") == 0) {
722 if (dir_filler(filler
, buf
, ".", 0) != 0 ||
723 dir_filler(filler
, buf
, "..", 0) != 0 ||
724 dir_filler(filler
, buf
, "proc", 0) != 0 ||
725 dir_filler(filler
, buf
, "sys", 0) != 0 ||
726 dir_filler(filler
, buf
, "cgroup", 0) != 0)
732 if (strncmp(path
, "/cgroup", 7) == 0) {
734 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
739 if (strcmp(path
, "/proc") == 0) {
741 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
746 if (strncmp(path
, "/sys", 4) == 0) {
748 ret
= do_sys_readdir(path
, buf
, filler
, offset
, fi
);
756 static int lxcfs_access(const char *path
, int mode
)
760 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
763 if (strncmp(path
, "/cgroup", 7) == 0) {
765 ret
= do_cg_access(path
, mode
);
770 if (strncmp(path
, "/proc", 5) == 0) {
772 ret
= do_proc_access(path
, mode
);
777 if (strncmp(path
, "/sys", 4) == 0) {
779 ret
= do_sys_access(path
, mode
);
787 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
790 enum lxcfs_virt_t type
;
792 type
= file_info_type(fi
);
794 if (LXCFS_TYPE_CGROUP(type
)) {
796 ret
= do_cg_releasedir(path
, fi
);
801 if (LXCFS_TYPE_SYS(type
)) {
803 ret
= do_sys_releasedir(path
, fi
);
809 if (strcmp(path
, "/") == 0)
811 if (strcmp(path
, "/proc") == 0)
815 lxcfs_error("unknown file type: path=%s, type=%d, fi->fh=%" PRIu64
,
821 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
825 if (strncmp(path
, "/cgroup", 7) == 0) {
827 ret
= do_cg_open(path
, fi
);
832 if (strncmp(path
, "/proc", 5) == 0) {
834 ret
= do_proc_open(path
, fi
);
839 if (strncmp(path
, "/sys", 4) == 0) {
841 ret
= do_sys_open(path
, fi
);
849 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
850 struct fuse_file_info
*fi
)
854 if (strncmp(path
, "/cgroup", 7) == 0) {
856 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
861 if (strncmp(path
, "/proc", 5) == 0) {
863 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
868 if (strncmp(path
, "/sys", 4) == 0) {
870 ret
= do_sys_read(path
, buf
, size
, offset
, fi
);
878 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
879 struct fuse_file_info
*fi
)
883 if (strncmp(path
, "/cgroup", 7) == 0) {
885 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
890 if (strncmp(path
, "/sys", 4) == 0) {
892 ret
= do_sys_write(path
, buf
, size
, offset
, fi
);
900 int lxcfs_readlink(const char *path
, char *buf
, size_t size
)
904 if (strncmp(path
, "/sys", 4) == 0) {
906 ret
= do_sys_readlink(path
, buf
, size
);
914 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
919 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
922 enum lxcfs_virt_t type
;
924 type
= file_info_type(fi
);
926 if (LXCFS_TYPE_CGROUP(type
)) {
928 ret
= do_cg_release(path
, fi
);
933 if (LXCFS_TYPE_PROC(type
)) {
935 ret
= do_proc_release(path
, fi
);
940 if (LXCFS_TYPE_SYS(type
)) {
942 ret
= do_sys_release(path
, fi
);
947 lxcfs_error("unknown file type: path=%s, type=%d, fi->fh=%" PRIu64
,
953 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
958 int lxcfs_mkdir(const char *path
, mode_t mode
)
962 if (strncmp(path
, "/cgroup", 7) == 0) {
964 ret
= do_cg_mkdir(path
, mode
);
973 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
, struct fuse_file_info
*fi
)
975 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
980 if (strncmp(path
, "/cgroup", 7) == 0) {
982 ret
= do_cg_chown(path
, uid
, gid
);
987 if (strncmp(path
, "/proc", 5) == 0)
990 if (strncmp(path
, "/sys", 4) == 0)
997 * cat first does a truncate before doing ops->write. This doesn't
998 * really make sense for cgroups. So just return 0 always but do
1002 int lxcfs_truncate(const char *path
, off_t newsize
, struct fuse_file_info
*fi
)
1004 int lxcfs_truncate(const char *path
, off_t newsize
)
1007 if (strncmp(path
, "/cgroup", 7) == 0)
1010 if (strncmp(path
, "/sys", 4) == 0)
1016 int lxcfs_rmdir(const char *path
)
1020 if (strncmp(path
, "/cgroup", 7) == 0) {
1022 ret
= do_cg_rmdir(path
);
1031 int lxcfs_chmod(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
1033 int lxcfs_chmod(const char *path
, mode_t mode
)
1038 if (strncmp(path
, "/cgroup", 7) == 0) {
1040 ret
= do_cg_chmod(path
, mode
);
1045 if (strncmp(path
, "/proc", 5) == 0)
1048 if (strncmp(path
, "/sys", 4) == 0)
1055 static void *lxcfs_init(struct fuse_conn_info
*conn
, struct fuse_config
*cfg
)
1057 static void *lxcfs_init(struct fuse_conn_info
*conn
)
1060 if (lxcfs_init_library() < 0)
1067 return fuse_get_context()->private_data
;
1070 const struct fuse_operations lxcfs_ops
= {
1071 .access
= lxcfs_access
,
1072 .chmod
= lxcfs_chmod
,
1073 .chown
= lxcfs_chown
,
1074 .flush
= lxcfs_flush
,
1075 .fsync
= lxcfs_fsync
,
1076 .getattr
= lxcfs_getattr
,
1078 .mkdir
= lxcfs_mkdir
,
1080 .opendir
= lxcfs_opendir
,
1082 .readdir
= lxcfs_readdir
,
1083 .release
= lxcfs_release
,
1084 .releasedir
= lxcfs_releasedir
,
1085 .rmdir
= lxcfs_rmdir
,
1086 .truncate
= lxcfs_truncate
,
1087 .write
= lxcfs_write
,
1088 .readlink
= lxcfs_readlink
,
1105 .removexattr
= NULL
,
1115 static void usage(void)
1117 lxcfs_info("Usage: lxcfs <directory>\n");
1118 lxcfs_info("lxcfs is a FUSE-based proc, sys and cgroup virtualizing filesystem\n");
1119 lxcfs_info("Options :");
1120 lxcfs_info(" -d, --debug Run lxcfs with debugging enabled");
1121 lxcfs_info(" -f, --foreground Run lxcfs in the foreground");
1122 lxcfs_info(" -n, --help Print help");
1123 lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization");
1124 lxcfs_info(" -o Options to pass directly through fuse");
1125 lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid");
1126 lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH
);
1127 lxcfs_info(" -u, --disable-swap Disable swap virtualization");
1128 lxcfs_info(" -v, --version Print lxcfs version");
1129 lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares");
1130 lxcfs_info(" --enable-pidfd Use pidfd for process tracking");
1134 static int set_pidfile(char *pidfile
)
1136 __do_close
int fd
= -EBADF
;
1137 char buf
[INTTYPE_TO_STRLEN(long)];
1141 .l_whence
= SEEK_SET
,
1146 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
| O_CLOEXEC
);
1148 return log_error(-1, "Could not open pidfile %s: %m", pidfile
);
1150 if (fcntl(fd
, F_SETLK
, &fl
) < 0) {
1151 if (errno
== EAGAIN
|| errno
== EACCES
)
1152 return log_error(-1, "PID file '%s' is already locked", pidfile
);
1153 lxcfs_error("Warning; unable to lock PID file, proceeding");
1156 if (ftruncate(fd
, 0))
1157 return log_error(-1, "Error truncating PID file '%s': %m", pidfile
);
1159 ret
= snprintf(buf
, sizeof(buf
), "%ld\n", (long)getpid());
1160 if (ret
< 0 || (size_t)ret
>= sizeof(buf
))
1161 return log_error(-1, "Failed to convert pid to string %m");
1163 if (write(fd
, buf
, ret
) != ret
)
1164 return log_error(-1, "Error writing to PID file '%s': %m", pidfile
);
1169 static const struct option long_options
[] = {
1170 {"debug", no_argument
, 0, 'd' },
1171 {"disable-swap", no_argument
, 0, 'u' },
1172 {"enable-loadavg", no_argument
, 0, 'l' },
1173 {"foreground", no_argument
, 0, 'f' },
1174 {"help", no_argument
, 0, 'h' },
1175 {"version", no_argument
, 0, 'v' },
1177 {"enable-cfs", no_argument
, 0, 0 },
1178 {"enable-pidfd", no_argument
, 0, 0 },
1180 {"pidfile", required_argument
, 0, 'p' },
1184 static int append_comma_separate(char **s
, const char *append
)
1188 size_t append_len
, len
;
1193 append_len
= strlen(append
);
1199 news
= realloc(*s
, len
+ append_len
+ 2);
1202 news
= realloc(NULL
, append_len
+ 1);
1208 ret
= snprintf(news
+ len
, append_len
+ 2, ",%s", append
);
1210 ret
= snprintf(news
, append_len
+ 1, "%s", append
);
1218 int main(int argc
, char *argv
[])
1220 int pidfile_fd
= -EBADF
;
1221 int ret
= EXIT_FAILURE
;
1222 char *pidfile
= NULL
, *token
= NULL
;
1223 char pidfile_buf
[STRLITERALLEN(RUNTIME_PATH
) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
1224 bool debug
= false, foreground
= false;
1226 bool nonempty
= false;
1228 bool load_use
= false;
1230 * what we pass to fuse_main is:
1231 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
1234 int c
, idx
, new_argc
;
1236 const char *fuse_opts
= NULL
;
1237 char *new_fuse_opts
= NULL
;
1238 char *const *new_argv
;
1239 struct lxcfs_opts
*opts
;
1241 opts
= malloc(sizeof(struct lxcfs_opts
));
1243 lxcfs_error("Error allocating memory for options");
1247 opts
->swap_off
= false;
1248 opts
->use_pidfd
= false;
1249 opts
->use_cfs
= false;
1252 while ((c
= getopt_long(argc
, argv
, "dulfhvso:p:", long_options
, &idx
)) != -1) {
1255 if (strcmp(long_options
[idx
].name
, "enable-pidfd") == 0)
1256 opts
->use_pidfd
= true;
1257 else if (strcmp(long_options
[idx
].name
, "enable-cfs") == 0)
1258 opts
->use_cfs
= true;
1273 lxcfs_error("Specifying -o multiple times is unsupported");
1283 /* legacy argument: ignore */
1286 opts
->swap_off
= true;
1289 lxcfs_info("%s", STRINGIFY(PROJECT_VERSION
));
1296 if (foreground
&& debug
)
1297 log_exit("Both --debug and --forgreound specified");
1299 new_argv
= &argv
[optind
];
1300 new_argc
= argc
- optind
;
1302 /* Older LXCFS versions printed help when used without any argument. */
1306 if (new_argc
!= 1) {
1307 lxcfs_error("Missing mountpoint");
1311 fuse_argv
[fuse_argc
++] = argv
[0];
1313 fuse_argv
[fuse_argc
++] = "-d";
1315 fuse_argv
[fuse_argc
++] = "-f";
1316 fuse_argv
[fuse_argc
++] = "-o";
1318 /* Parse additional fuse options. */
1322 dup
= strdup(fuse_opts
);
1324 lxcfs_error("Failed to copy fuse options");
1328 lxc_iterate_parts(token
, dup
, ",") {
1330 if (strcmp(token
, "allow_other") == 0)
1333 /* default for LXCFS */
1334 if (strcmp(token
, "direct_io") == 0)
1337 /* default for LXCFS */
1338 if (strncmp(token
, "entry_timeout", STRLITERALLEN("entry_timeout")) == 0)
1341 /* default for LXCFS */
1342 if (strncmp(token
, "attr_timeout", STRLITERALLEN("entry_timeout")) == 0)
1345 /* default for LXCFS */
1346 if (strncmp(token
, "allow_other", STRLITERALLEN("allow_other")) == 0)
1349 /* default with fuse3 */
1350 if (strcmp(token
, "nonempty") == 0) {
1357 if (append_comma_separate(&new_fuse_opts
, token
)) {
1358 lxcfs_error("Failed to copy fuse argument \"%s\"", token
);
1366 if (append_comma_separate(&new_fuse_opts
, "allow_other,entry_timeout=0.5,attr_timeout=0.5")) {
1367 lxcfs_error("Failed to copy fuse argument \"allow_other,entry_timeout=0.5,attr_timeout=0.5\"");
1373 if (append_comma_separate(&new_fuse_opts
, "nonempty")) {
1374 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1379 if (append_comma_separate(&new_fuse_opts
, "direct_io")) {
1380 lxcfs_error("Failed to copy fuse argument \"direct_io\"");
1386 * We can't use default_permissions since we still support systems that
1387 * don't have kernels with cgroup namespace support. On such kernels
1388 * lxcfs will provide a namespaced cgroup view and needs explicit
1389 * access helpers to make that work.
1390 * Another reason that came to me is that we can't or at least
1391 * shouldn't guarantee that we don't need more complicated access
1392 * helpers for proc and sys virtualization in the future.
1395 fuse_argv
[fuse_argc
++] = new_fuse_opts
;
1396 fuse_argv
[fuse_argc
++] = new_argv
[0];
1397 fuse_argv
[fuse_argc
] = NULL
;
1400 if (install_signal_handler(SIGUSR1
, sigusr1_reload
)) {
1401 lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno
));
1406 snprintf(pidfile_buf
, sizeof(pidfile_buf
), "%s/lxcfs.pid", RUNTIME_PATH
);
1407 pidfile
= pidfile_buf
;
1410 pidfile_fd
= set_pidfile(pidfile
);
1414 if (load_use
&& start_loadavg() != 0)
1417 if (!fuse_main(fuse_argc
, fuse_argv
, &lxcfs_ops
, opts
))
1425 dlclose(dlopen_handle
);
1428 free(new_fuse_opts
);
1430 close_prot_errno_disarm(pidfile_fd
);