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
38 #include <linux/sched.h>
39 #include <sys/epoll.h>
40 #include <sys/mount.h>
41 #include <sys/socket.h>
42 #include <linux/limits.h>
45 #include "lxcfs_fuse_compat.h"
47 #include "memory_utils.h"
51 /* Functions to keep track of number of threads using the library */
53 static int users_count
;
54 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
55 static void lock_mutex(pthread_mutex_t
*l
)
59 ret
= pthread_mutex_lock(l
);
61 log_exit("%s - returned: %d\n", strerror(ret
), ret
);
64 static void unlock_mutex(pthread_mutex_t
*l
)
68 ret
= pthread_mutex_unlock(l
);
70 log_exit("%s - returned: %d\n", strerror(ret
), ret
);
73 static inline void users_lock(void)
75 lock_mutex(&user_count_mutex
);
78 static inline void users_unlock(void)
80 unlock_mutex(&user_count_mutex
);
83 static pthread_t loadavg_pid
= 0;
85 /* Returns zero on success */
86 static int start_loadavg(void)
89 pthread_t (*__load_daemon
)(int);
92 __load_daemon
= (pthread_t(*)(int))dlsym(dlopen_handle
, "load_daemon");
95 return log_error(-1, "%s - Failed to start loadavg daemon", error
);
97 loadavg_pid
= __load_daemon(1);
104 /* Returns zero on success */
105 static int stop_loadavg(void)
108 int (*__stop_load_daemon
)(pthread_t
);
110 __stop_load_daemon
= (int (*)(pthread_t
))dlsym(dlopen_handle
, "stop_load_daemon");
113 return log_error(-1, "%s - Failed to stop loadavg daemon", error
);
115 if (__stop_load_daemon(loadavg_pid
))
121 static volatile sig_atomic_t need_reload
;
123 /* do_reload - reload the dynamic library. Done under
124 * lock and when we know the user_count was 0 */
125 static void do_reload(void)
128 char lxcfs_lib_path
[PATH_MAX
];
134 lxcfs_info("Closed liblxcfs.so");
135 dlclose(dlopen_handle
);
138 /* First try loading using ld.so */
140 dlopen_handle
= dlopen("liblxcfs.so", RTLD_NOW
);
142 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
145 lxcfs_debug("Opened liblxcfs.so");
150 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
151 ret
= snprintf(lxcfs_lib_path
, sizeof(lxcfs_lib_path
), "%s/lxcfs/liblxcfs.so", LIBDIR
);
153 ret
= snprintf(lxcfs_lib_path
, sizeof(lxcfs_lib_path
), "/usr/local/lib/lxcfs/liblxcfs.so");
155 if (ret
< 0 || ret
>= sizeof(lxcfs_lib_path
))
156 log_exit("Failed to create path to open liblxcfs");
158 dlopen_handle
= dlopen(lxcfs_lib_path
, RTLD_LAZY
);
160 log_exit("%s - Failed to open liblxcfs.so", dlerror());
162 lxcfs_debug("Opened %s", lxcfs_lib_path
);
169 lxcfs_info("Reloaded LXCFS");
173 static void up_users(void)
176 if (users_count
== 0 && need_reload
)
182 static void down_users(void)
189 static void sigusr1_reload(int signo
, siginfo_t
*info
, void *extra
)
194 /* Functions to run the library methods */
195 static int do_cg_getattr(const char *path
, struct stat
*sb
)
198 int (*__cg_getattr
)(const char *path
, struct stat
*sb
);
201 __cg_getattr
= (int (*)(const char *, struct stat
*))dlsym(dlopen_handle
, "cg_getattr");
204 return log_error(-1, "%s - Failed to find cg_getattr()", error
);
206 return __cg_getattr(path
, sb
);
209 static int do_proc_getattr(const char *path
, struct stat
*sb
)
212 int (*__proc_getattr
)(const char *path
, struct stat
*sb
);
215 __proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
218 return log_error(-1, "%s - Failed to find proc_getattr()", error
);
220 return __proc_getattr(path
, sb
);
223 static int do_sys_getattr(const char *path
, struct stat
*sb
)
226 int (*__sys_getattr
)(const char *path
, struct stat
*sb
);
229 __sys_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "sys_getattr");
232 return log_error(-1, "%s - Failed to find sys_getattr()", error
);
234 return __sys_getattr(path
, sb
);
237 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
238 struct fuse_file_info
*fi
)
241 int (*__cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
242 struct fuse_file_info
*fi
);
245 __cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_read");
248 return log_error(-1, "%s - Failed to find cg_read()", error
);
250 return __cg_read(path
, buf
, size
, offset
, fi
);
253 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
254 struct fuse_file_info
*fi
)
257 int (*__proc_read
)(const char *path
, char *buf
, size_t size
,
258 off_t offset
, struct fuse_file_info
*fi
);
261 __proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "proc_read");
264 return log_error(-1, "%s - Failed to find proc_read()", error
);
266 return __proc_read(path
, buf
, size
, offset
, fi
);
269 static int do_sys_read(const char *path
, char *buf
, size_t size
, off_t offset
,
270 struct fuse_file_info
*fi
)
273 int (*__sys_read
)(const char *path
, char *buf
, size_t size
,
274 off_t offset
, struct fuse_file_info
*fi
);
277 __sys_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_read");
280 return log_error(-1, "%s - Failed to find sys_read()", error
);
282 return __sys_read(path
, buf
, size
, offset
, fi
);
285 static int do_cg_write(const char *path
, const char *buf
, size_t size
,
286 off_t offset
, struct fuse_file_info
*fi
)
289 int (*__cg_write
)(const char *path
, const char *buf
, size_t size
,
290 off_t offset
, struct fuse_file_info
*fi
);
293 __cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_write");
296 return log_error(-1, "%s - Failed to find cg_write()", error
);
298 return __cg_write(path
, buf
, size
, offset
, fi
);
301 static int do_cg_mkdir(const char *path
, mode_t mode
)
304 int (*__cg_mkdir
)(const char *path
, mode_t mode
);
307 __cg_mkdir
= (int (*)(const char *, mode_t
))dlsym(dlopen_handle
, "cg_mkdir");
310 return log_error(-1, "%s - Failed to find cg_mkdir()", error
);
312 return __cg_mkdir(path
, mode
);
315 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
318 int (*__cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
321 __cg_chown
= (int (*)(const char *, uid_t
, gid_t
))dlsym(dlopen_handle
, "cg_chown");
324 return log_error(-1, "%s - Failed to find cg_chown()", error
);
326 return __cg_chown(path
, uid
, gid
);
329 static int do_cg_rmdir(const char *path
)
332 int (*__cg_rmdir
)(const char *path
);
335 __cg_rmdir
= (int (*)(const char *path
))dlsym(dlopen_handle
, "cg_rmdir");
338 return log_error(-1, "%s - Failed to find cg_rmdir()", error
);
340 return __cg_rmdir(path
);
343 static int do_cg_chmod(const char *path
, mode_t mode
)
346 int (*__cg_chmod
)(const char *path
, mode_t mode
);
349 __cg_chmod
= (int (*)(const char *, mode_t
))dlsym(dlopen_handle
, "cg_chmod");
352 return log_error(-1, "%s - Failed to find cg_chmod()", error
);
354 return __cg_chmod(path
, mode
);
357 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
358 off_t offset
, struct fuse_file_info
*fi
)
361 int (*__cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
362 off_t offset
, struct fuse_file_info
*fi
);
365 __cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_readdir");
368 return log_error(-1, "%s - Failed to find cg_readdir()", error
);
370 return __cg_readdir(path
, buf
, filler
, offset
, fi
);
373 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
374 off_t offset
, struct fuse_file_info
*fi
)
377 int (*__proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
378 off_t offset
, struct fuse_file_info
*fi
);
381 __proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "proc_readdir");
384 return log_error(-1, "%s - Failed to find proc_readdir()", error
);
386 return __proc_readdir(path
, buf
, filler
, offset
, fi
);
389 static int do_sys_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
390 off_t offset
, struct fuse_file_info
*fi
)
393 int (*__sys_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
394 off_t offset
, struct fuse_file_info
*fi
);
397 __sys_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_readdir");
400 return log_error(-1, "%s - Failed to find sys_readdir()", error
);
402 return __sys_readdir(path
, buf
, filler
, offset
, fi
);
406 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
409 int (*__cg_open
)(const char *path
, struct fuse_file_info
*fi
);
412 __cg_open
= (int (*)(const char *, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_open");
415 return log_error(-1, "%s - Failed to find cg_open()", error
);
417 return __cg_open(path
, fi
);
420 static int do_cg_access(const char *path
, int mode
)
423 int (*__cg_access
)(const char *path
, int mode
);
426 __cg_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "cg_access");
429 return log_error(-1, "%s - Failed to find cg_access()", error
);
431 return __cg_access(path
, mode
);
434 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
437 int (*__proc_open
)(const char *path
, struct fuse_file_info
*fi
);
440 __proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "proc_open");
443 return log_error(-1, "%s - Failed to find proc_open()", error
);
445 return __proc_open(path
, fi
);
448 static int do_proc_access(const char *path
, int mode
)
451 int (*__proc_access
)(const char *path
, int mode
);
454 __proc_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "proc_access");
457 return log_error(-1, "%s - Failed to find proc_access()", error
);
459 return __proc_access(path
, mode
);
462 static int do_sys_open(const char *path
, struct fuse_file_info
*fi
)
465 int (*__sys_open
)(const char *path
, struct fuse_file_info
*fi
);
468 __sys_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "sys_open");
471 return log_error(-1, "%s - Failed to find sys_open()", error
);
473 return __sys_open(path
, fi
);
476 static int do_sys_access(const char *path
, int mode
)
479 int (*__sys_access
)(const char *path
, int mode
);
482 __sys_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "sys_access");
485 return log_error(-1, "%s - Failed to find sys_access()", error
);
487 return __sys_access(path
, mode
);
490 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
493 int (*__cg_release
)(const char *path
, struct fuse_file_info
*fi
);
496 __cg_release
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_release");
499 return log_error(-1, "%s - Failed to find cg_release()", error
);
501 return __cg_release(path
, fi
);
504 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
507 int (*__proc_release
)(const char *path
, struct fuse_file_info
*fi
);
510 __proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
513 return log_error(-1, "%s - Failed to find proc_release()", error
);
515 return __proc_release(path
, fi
);
518 static int do_sys_release(const char *path
, struct fuse_file_info
*fi
)
521 int (*__sys_release
)(const char *path
, struct fuse_file_info
*fi
);
524 __sys_release
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_release");
527 return log_error(-1, "%s - Failed to find sys_release()", error
);
529 return __sys_release(path
, fi
);
532 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
535 int (*__cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
538 __cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "cg_opendir");
541 return log_error(-1, "%s - Failed to find cg_opendir()", error
);
543 return __cg_opendir(path
, fi
);
546 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
549 int (*__cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
552 __cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_releasedir");
555 return log_error(-1, "%s - Failed to find cg_releasedir()", error
);
557 return __cg_releasedir(path
, fi
);
560 static int do_sys_releasedir(const char *path
, struct fuse_file_info
*fi
)
563 int (*__sys_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
566 __sys_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_releasedir");
569 return log_error(-1, "%s - Failed to find sys_releasedir()", error
);
571 return __sys_releasedir(path
, fi
);
575 static int lxcfs_getattr(const char *path
, struct stat
*sb
, struct fuse_file_info
*fi
)
577 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
583 if (strcmp(path
, "/") == 0) {
584 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
586 sb
->st_uid
= sb
->st_gid
= 0;
587 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
589 sb
->st_mode
= S_IFDIR
| 00755;
594 if (strncmp(path
, "/cgroup", 7) == 0) {
596 ret
= do_cg_getattr(path
, sb
);
601 if (strncmp(path
, "/proc", 5) == 0) {
603 ret
= do_proc_getattr(path
, sb
);
608 if (strncmp(path
, "/sys", 4) == 0) {
610 ret
= do_sys_getattr(path
, sb
);
618 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
622 if (strcmp(path
, "/") == 0)
625 if (strncmp(path
, "/cgroup", 7) == 0) {
627 ret
= do_cg_opendir(path
, fi
);
632 if (strcmp(path
, "/proc") == 0)
635 if (strncmp(path
, "/sys", 4) == 0)
642 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
643 off_t offset
, struct fuse_file_info
*fi
, enum fuse_readdir_flags flags
)
645 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
646 off_t offset
, struct fuse_file_info
*fi
)
651 if (strcmp(path
, "/") == 0) {
652 if (DIR_FILLER(filler
, buf
, ".", NULL
, 0) != 0 ||
653 DIR_FILLER(filler
, buf
, "..", NULL
, 0) != 0 ||
654 DIR_FILLER(filler
, buf
, "proc", NULL
, 0) != 0 ||
655 DIR_FILLER(filler
, buf
, "sys", NULL
, 0) != 0 ||
656 DIR_FILLER(filler
, buf
, "cgroup", NULL
, 0) != 0)
662 if (strncmp(path
, "/cgroup", 7) == 0) {
664 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
669 if (strcmp(path
, "/proc") == 0) {
671 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
676 if (strncmp(path
, "/sys", 4) == 0) {
678 ret
= do_sys_readdir(path
, buf
, filler
, offset
, fi
);
686 static int lxcfs_access(const char *path
, int mode
)
690 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
693 if (strncmp(path
, "/cgroup", 7) == 0) {
695 ret
= do_cg_access(path
, mode
);
700 if (strncmp(path
, "/proc", 5) == 0) {
702 ret
= do_proc_access(path
, mode
);
707 if (strncmp(path
, "/sys", 4) == 0) {
709 ret
= do_sys_access(path
, mode
);
717 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
721 if (strcmp(path
, "/") == 0)
724 if (strncmp(path
, "/cgroup", 7) == 0) {
726 ret
= do_cg_releasedir(path
, fi
);
731 if (strcmp(path
, "/proc") == 0)
734 if (strncmp(path
, "/sys", 4) == 0) {
736 ret
= do_sys_releasedir(path
, fi
);
744 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
748 if (strncmp(path
, "/cgroup", 7) == 0) {
750 ret
= do_cg_open(path
, fi
);
755 if (strncmp(path
, "/proc", 5) == 0) {
757 ret
= do_proc_open(path
, fi
);
762 if (strncmp(path
, "/sys", 4) == 0) {
764 ret
= do_sys_open(path
, fi
);
772 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
773 struct fuse_file_info
*fi
)
777 if (strncmp(path
, "/cgroup", 7) == 0) {
779 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
784 if (strncmp(path
, "/proc", 5) == 0) {
786 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
791 if (strncmp(path
, "/sys", 4) == 0) {
793 ret
= do_sys_read(path
, buf
, size
, offset
, fi
);
801 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
802 struct fuse_file_info
*fi
)
806 if (strncmp(path
, "/cgroup", 7) == 0) {
808 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
816 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
821 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
825 if (strncmp(path
, "/cgroup", 7) == 0) {
827 ret
= do_cg_release(path
, fi
);
832 if (strncmp(path
, "/proc", 5) == 0) {
834 ret
= do_proc_release(path
, fi
);
839 if (strncmp(path
, "/sys", 4) == 0) {
841 ret
= do_sys_release(path
, fi
);
849 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
854 int lxcfs_mkdir(const char *path
, mode_t mode
)
858 if (strncmp(path
, "/cgroup", 7) == 0) {
860 ret
= do_cg_mkdir(path
, mode
);
869 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
, struct fuse_file_info
*fi
)
871 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
876 if (strncmp(path
, "/cgroup", 7) == 0) {
878 ret
= do_cg_chown(path
, uid
, gid
);
883 if (strncmp(path
, "/proc", 5) == 0)
886 if (strncmp(path
, "/sys", 4) == 0)
893 * cat first does a truncate before doing ops->write. This doesn't
894 * really make sense for cgroups. So just return 0 always but do
898 int lxcfs_truncate(const char *path
, off_t newsize
, struct fuse_file_info
*fi
)
900 int lxcfs_truncate(const char *path
, off_t newsize
)
903 if (strncmp(path
, "/cgroup", 7) == 0)
909 int lxcfs_rmdir(const char *path
)
913 if (strncmp(path
, "/cgroup", 7) == 0) {
915 ret
= do_cg_rmdir(path
);
924 int lxcfs_chmod(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
926 int lxcfs_chmod(const char *path
, mode_t mode
)
931 if (strncmp(path
, "/cgroup", 7) == 0) {
933 ret
= do_cg_chmod(path
, mode
);
938 if (strncmp(path
, "/proc", 5) == 0)
941 if (strncmp(path
, "/sys", 4) == 0)
947 const struct fuse_operations lxcfs_ops
= {
948 .access
= lxcfs_access
,
949 .chmod
= lxcfs_chmod
,
950 .chown
= lxcfs_chown
,
951 .flush
= lxcfs_flush
,
952 .fsync
= lxcfs_fsync
,
953 .getattr
= lxcfs_getattr
,
954 .mkdir
= lxcfs_mkdir
,
956 .opendir
= lxcfs_opendir
,
958 .readdir
= lxcfs_readdir
,
959 .release
= lxcfs_release
,
960 .releasedir
= lxcfs_releasedir
,
961 .rmdir
= lxcfs_rmdir
,
962 .truncate
= lxcfs_truncate
,
963 .write
= lxcfs_write
,
994 lxcfs_info("Usage: lxcfs <directory>\n");
995 lxcfs_info("lxcfs is a FUSE-based proc, sys and cgroup virtualizing filesystem\n");
996 lxcfs_info("Options :");
997 lxcfs_info(" -d, --debug Run lxcfs with debugging enabled");
998 lxcfs_info(" -f, --foreground Run lxcfs in the foreground");
999 lxcfs_info(" -n, --help Print help");
1000 lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization");
1001 lxcfs_info(" -o Options to pass directly through fuse");
1002 lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid");
1003 lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH
);
1004 lxcfs_info(" -u, --disable-swap Disable swap virtualization");
1005 lxcfs_info(" -v, --version Print lxcfs version");
1006 lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares");
1007 lxcfs_info(" --enable-pidfd Use pidfd for process tracking");
1011 static int set_pidfile(char *pidfile
)
1013 __do_close
int fd
= -EBADF
;
1014 char buf
[INTTYPE_TO_STRLEN(long)];
1018 .l_whence
= SEEK_SET
,
1023 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
| O_CLOEXEC
);
1025 return log_error(-1, "Could not open pidfile %s: %m", pidfile
);
1027 if (fcntl(fd
, F_SETLK
, &fl
) < 0) {
1028 if (errno
== EAGAIN
|| errno
== EACCES
)
1029 return log_error(-1, "PID file '%s' is already locked", pidfile
);
1030 lxcfs_error("Warning; unable to lock PID file, proceeding");
1033 if (ftruncate(fd
, 0))
1034 return log_error(-1, "Error truncating PID file '%s': %m", pidfile
);
1036 ret
= snprintf(buf
, sizeof(buf
), "%ld\n", (long)getpid());
1037 if (ret
< 0 || ret
>= sizeof(buf
))
1038 return log_error(-1, "Failed to convert pid to string %m");
1040 if (write(fd
, buf
, ret
) != ret
)
1041 return log_error(-1, "Error writing to PID file '%s': %m", pidfile
);
1046 static const struct option long_options
[] = {
1047 {"debug", no_argument
, 0, 'd' },
1048 {"disable-swap", no_argument
, 0, 'u' },
1049 {"enable-loadavg", no_argument
, 0, 'l' },
1050 {"foreground", no_argument
, 0, 'f' },
1051 {"help", no_argument
, 0, 'h' },
1052 {"version", no_argument
, 0, 'v' },
1054 {"enable-cfs", no_argument
, 0, 0 },
1055 {"enable-pidfd", no_argument
, 0, 0 },
1057 {"pidfile", required_argument
, 0, 'p' },
1061 static int append_comma_separate(char **s
, const char *append
)
1065 size_t append_len
, len
;
1070 append_len
= strlen(append
);
1076 news
= realloc(*s
, len
+ append_len
+ 2);
1079 news
= realloc(NULL
, append_len
+ 1);
1085 ret
= snprintf(news
+ len
, append_len
+ 2, ",%s", append
);
1087 ret
= snprintf(news
, append_len
+ 1, "%s", append
);
1095 int main(int argc
, char *argv
[])
1097 int pidfile_fd
= -EBADF
;
1098 int ret
= EXIT_FAILURE
;
1099 char *pidfile
= NULL
, *token
= NULL
;
1100 char pidfile_buf
[STRLITERALLEN(RUNTIME_PATH
) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
1101 bool debug
= false, foreground
= false;
1103 bool nonempty
= false;
1105 bool load_use
= false;
1107 * what we pass to fuse_main is:
1108 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
1111 int c
, idx
, new_argc
;
1113 const char *fuse_opts
= NULL
;
1114 char *new_fuse_opts
= NULL
;
1115 char *const *new_argv
;
1116 struct lxcfs_opts
*opts
;
1118 opts
= malloc(sizeof(struct lxcfs_opts
));
1120 lxcfs_error("Error allocating memory for options");
1124 opts
->swap_off
= false;
1125 opts
->use_pidfd
= false;
1126 opts
->use_cfs
= false;
1128 while ((c
= getopt_long(argc
, argv
, "dulfhvso:p:", long_options
, &idx
)) != -1) {
1131 if (strcmp(long_options
[idx
].name
, "enable-pidfd") == 0)
1132 opts
->use_pidfd
= true;
1133 else if (strcmp(long_options
[idx
].name
, "enable-cfs") == 0)
1134 opts
->use_cfs
= true;
1149 lxcfs_error("Specifying -o multiple times is unsupported");
1159 /* legacy argument: ignore */
1162 opts
->swap_off
= true;
1169 if (foreground
&& debug
)
1170 log_exit("Both --debug and --forgreound specified");
1172 new_argv
= &argv
[optind
];
1173 new_argc
= argc
- optind
;
1174 if (new_argc
!= 1) {
1175 lxcfs_error("Missing mountpoint");
1179 fuse_argv
[fuse_argc
++] = argv
[0];
1181 fuse_argv
[fuse_argc
++] = "-d";
1183 fuse_argv
[fuse_argc
++] = "-f";
1184 fuse_argv
[fuse_argc
++] = "-o";
1186 /* Parse additional fuse options. */
1190 dup
= strdup(fuse_opts
);
1192 lxcfs_error("Failed to copy fuse options");
1196 lxc_iterate_parts(token
, dup
, ",") {
1198 if (strcmp(token
, "allow_other") == 0)
1201 /* default for LXCFS */
1202 if (strcmp(token
, "direct_io") == 0)
1205 /* default for LXCFS */
1206 if (strncmp(token
, "entry_timeout", STRLITERALLEN("entry_timeout")) == 0)
1209 /* default for LXCFS */
1210 if (strncmp(token
, "attr_timeout", STRLITERALLEN("entry_timeout")) == 0)
1213 /* default for LXCFS */
1214 if (strncmp(token
, "allow_other", STRLITERALLEN("allow_other")) == 0)
1217 /* default with fuse3 */
1218 if (strcmp(token
, "nonempty") == 0) {
1225 if (append_comma_separate(&new_fuse_opts
, token
)) {
1226 lxcfs_error("Failed to copy fuse argument \"%s\"", token
);
1234 if (append_comma_separate(&new_fuse_opts
, "allow_other,entry_timeout=0.5,attr_timeout=0.5")) {
1235 lxcfs_error("Failed to copy fuse argument \"allow_other,entry_timeout=0.5,attr_timeout=0.5\"");
1241 if (append_comma_separate(&new_fuse_opts
, "nonempty")) {
1242 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1247 if (append_comma_separate(&new_fuse_opts
, "direct_io")) {
1248 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1254 * We can't use default_permissions since we still support systems that
1255 * don't have kernels with cgroup namespace support. On such kernels
1256 * lxcfs will provide a namespaced cgroup view and needs explicit
1257 * access helpers to make that work.
1258 * Another reason that came to me is that we can't or at least
1259 * shouldn't guarantee that we don't need more complicated access
1260 * helpers for proc and sys virtualization in the future.
1263 fuse_argv
[fuse_argc
++] = new_fuse_opts
;
1264 fuse_argv
[fuse_argc
++] = new_argv
[0];
1265 fuse_argv
[fuse_argc
] = NULL
;
1267 for (int i
= 0; i
< fuse_argc
; i
++)
1268 printf("AAAA: %s\n", fuse_argv
[i
]);
1271 if (install_signal_handler(SIGUSR1
, sigusr1_reload
)) {
1272 lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno
));
1277 snprintf(pidfile_buf
, sizeof(pidfile_buf
), "%s/lxcfs.pid", RUNTIME_PATH
);
1278 pidfile
= pidfile_buf
;
1281 pidfile_fd
= set_pidfile(pidfile
);
1285 if (load_use
&& start_loadavg() != 0)
1288 if (!fuse_main(fuse_argc
, fuse_argv
, &lxcfs_ops
, opts
))
1296 dlclose(dlopen_handle
);
1299 free(new_fuse_opts
);
1301 close_prot_errno_disarm(pidfile_fd
);