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
37 #include <linux/sched.h>
38 #include <sys/epoll.h>
39 #include <sys/mount.h>
40 #include <sys/socket.h>
41 #include <linux/limits.h>
44 #include "fuse_compat.h"
46 #include "memory_utils.h"
50 /* Functions to keep track of number of threads using the library */
52 static int users_count
;
53 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
54 static void lock_mutex(pthread_mutex_t
*l
)
58 ret
= pthread_mutex_lock(l
);
60 log_exit("%s - returned: %d\n", strerror(ret
), ret
);
63 static void unlock_mutex(pthread_mutex_t
*l
)
67 ret
= pthread_mutex_unlock(l
);
69 log_exit("%s - returned: %d\n", strerror(ret
), ret
);
72 static inline void users_lock(void)
74 lock_mutex(&user_count_mutex
);
77 static inline void users_unlock(void)
79 unlock_mutex(&user_count_mutex
);
82 static pthread_t loadavg_pid
= 0;
84 /* Returns zero on success */
85 static int start_loadavg(void)
88 pthread_t (*__load_daemon
)(int);
91 __load_daemon
= (pthread_t(*)(int))dlsym(dlopen_handle
, "load_daemon");
94 return log_error(-1, "%s - Failed to start loadavg daemon", error
);
96 loadavg_pid
= __load_daemon(1);
103 /* Returns zero on success */
104 static int stop_loadavg(void)
107 int (*__stop_load_daemon
)(pthread_t
);
109 __stop_load_daemon
= (int (*)(pthread_t
))dlsym(dlopen_handle
, "stop_load_daemon");
112 return log_error(-1, "%s - Failed to stop loadavg daemon", error
);
114 if (__stop_load_daemon(loadavg_pid
))
120 static volatile sig_atomic_t need_reload
;
122 /* do_reload - reload the dynamic library. Done under
123 * lock and when we know the user_count was 0 */
124 static void do_reload(void)
127 char lxcfs_lib_path
[PATH_MAX
];
133 lxcfs_info("Closed liblxcfs.so");
134 dlclose(dlopen_handle
);
137 /* First try loading using ld.so */
139 dlopen_handle
= dlopen("liblxcfs.so", RTLD_NOW
);
141 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
144 lxcfs_debug("Opened liblxcfs.so");
149 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
150 ret
= snprintf(lxcfs_lib_path
, sizeof(lxcfs_lib_path
), "%s/lxcfs/liblxcfs.so", LIBDIR
);
152 ret
= snprintf(lxcfs_lib_path
, sizeof(lxcfs_lib_path
), "/usr/local/lib/lxcfs/liblxcfs.so");
154 if (ret
< 0 || ret
>= sizeof(lxcfs_lib_path
))
155 log_exit("Failed to create path to open liblxcfs");
157 dlopen_handle
= dlopen(lxcfs_lib_path
, RTLD_LAZY
);
159 log_exit("%s - Failed to open liblxcfs.so", dlerror());
161 lxcfs_debug("Opened %s", lxcfs_lib_path
);
168 lxcfs_info("Reloaded LXCFS");
172 static void up_users(void)
175 if (users_count
== 0 && need_reload
)
181 static void down_users(void)
188 static void sigusr1_reload(int signo
, siginfo_t
*info
, void *extra
)
193 /* Functions to run the library methods */
194 static int do_cg_getattr(const char *path
, struct stat
*sb
)
197 int (*__cg_getattr
)(const char *path
, struct stat
*sb
);
200 __cg_getattr
= (int (*)(const char *, struct stat
*))dlsym(dlopen_handle
, "cg_getattr");
203 return log_error(-1, "%s - Failed to find cg_getattr()", error
);
205 return __cg_getattr(path
, sb
);
208 static int do_proc_getattr(const char *path
, struct stat
*sb
)
211 int (*__proc_getattr
)(const char *path
, struct stat
*sb
);
214 __proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
217 return log_error(-1, "%s - Failed to find proc_getattr()", error
);
219 return __proc_getattr(path
, sb
);
222 static int do_sys_getattr(const char *path
, struct stat
*sb
)
225 int (*__sys_getattr
)(const char *path
, struct stat
*sb
);
228 __sys_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "sys_getattr");
231 return log_error(-1, "%s - Failed to find sys_getattr()", error
);
233 return __sys_getattr(path
, sb
);
236 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
237 struct fuse_file_info
*fi
)
240 int (*__cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
241 struct fuse_file_info
*fi
);
244 __cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_read");
247 return log_error(-1, "%s - Failed to find cg_read()", error
);
249 return __cg_read(path
, buf
, size
, offset
, fi
);
252 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
253 struct fuse_file_info
*fi
)
256 int (*__proc_read
)(const char *path
, char *buf
, size_t size
,
257 off_t offset
, struct fuse_file_info
*fi
);
260 __proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "proc_read");
263 return log_error(-1, "%s - Failed to find proc_read()", error
);
265 return __proc_read(path
, buf
, size
, offset
, fi
);
268 static int do_sys_read(const char *path
, char *buf
, size_t size
, off_t offset
,
269 struct fuse_file_info
*fi
)
272 int (*__sys_read
)(const char *path
, char *buf
, size_t size
,
273 off_t offset
, struct fuse_file_info
*fi
);
276 __sys_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_read");
279 return log_error(-1, "%s - Failed to find sys_read()", error
);
281 return __sys_read(path
, buf
, size
, offset
, fi
);
284 static int do_cg_write(const char *path
, const char *buf
, size_t size
,
285 off_t offset
, struct fuse_file_info
*fi
)
288 int (*__cg_write
)(const char *path
, const char *buf
, size_t size
,
289 off_t offset
, struct fuse_file_info
*fi
);
292 __cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_write");
295 return log_error(-1, "%s - Failed to find cg_write()", error
);
297 return __cg_write(path
, buf
, size
, offset
, fi
);
300 static int do_cg_mkdir(const char *path
, mode_t mode
)
303 int (*__cg_mkdir
)(const char *path
, mode_t mode
);
306 __cg_mkdir
= (int (*)(const char *, mode_t
))dlsym(dlopen_handle
, "cg_mkdir");
309 return log_error(-1, "%s - Failed to find cg_mkdir()", error
);
311 return __cg_mkdir(path
, mode
);
314 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
317 int (*__cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
320 __cg_chown
= (int (*)(const char *, uid_t
, gid_t
))dlsym(dlopen_handle
, "cg_chown");
323 return log_error(-1, "%s - Failed to find cg_chown()", error
);
325 return __cg_chown(path
, uid
, gid
);
328 static int do_cg_rmdir(const char *path
)
331 int (*__cg_rmdir
)(const char *path
);
334 __cg_rmdir
= (int (*)(const char *path
))dlsym(dlopen_handle
, "cg_rmdir");
337 return log_error(-1, "%s - Failed to find cg_rmdir()", error
);
339 return __cg_rmdir(path
);
342 static int do_cg_chmod(const char *path
, mode_t mode
)
345 int (*__cg_chmod
)(const char *path
, mode_t mode
);
348 __cg_chmod
= (int (*)(const char *, mode_t
))dlsym(dlopen_handle
, "cg_chmod");
351 return log_error(-1, "%s - Failed to find cg_chmod()", error
);
353 return __cg_chmod(path
, mode
);
356 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
357 off_t offset
, struct fuse_file_info
*fi
)
360 int (*__cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
361 off_t offset
, struct fuse_file_info
*fi
);
364 __cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_readdir");
367 return log_error(-1, "%s - Failed to find cg_readdir()", error
);
369 return __cg_readdir(path
, buf
, filler
, offset
, fi
);
372 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
373 off_t offset
, struct fuse_file_info
*fi
)
376 int (*__proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
377 off_t offset
, struct fuse_file_info
*fi
);
380 __proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "proc_readdir");
383 return log_error(-1, "%s - Failed to find proc_readdir()", error
);
385 return __proc_readdir(path
, buf
, filler
, offset
, fi
);
388 static int do_sys_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
389 off_t offset
, struct fuse_file_info
*fi
)
392 int (*__sys_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
393 off_t offset
, struct fuse_file_info
*fi
);
396 __sys_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_readdir");
399 return log_error(-1, "%s - Failed to find sys_readdir()", error
);
401 return __sys_readdir(path
, buf
, filler
, offset
, fi
);
405 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
408 int (*__cg_open
)(const char *path
, struct fuse_file_info
*fi
);
411 __cg_open
= (int (*)(const char *, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_open");
414 return log_error(-1, "%s - Failed to find cg_open()", error
);
416 return __cg_open(path
, fi
);
419 static int do_cg_access(const char *path
, int mode
)
422 int (*__cg_access
)(const char *path
, int mode
);
425 __cg_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "cg_access");
428 return log_error(-1, "%s - Failed to find cg_access()", error
);
430 return __cg_access(path
, mode
);
433 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
436 int (*__proc_open
)(const char *path
, struct fuse_file_info
*fi
);
439 __proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "proc_open");
442 return log_error(-1, "%s - Failed to find proc_open()", error
);
444 return __proc_open(path
, fi
);
447 static int do_proc_access(const char *path
, int mode
)
450 int (*__proc_access
)(const char *path
, int mode
);
453 __proc_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "proc_access");
456 return log_error(-1, "%s - Failed to find proc_access()", error
);
458 return __proc_access(path
, mode
);
461 static int do_sys_open(const char *path
, struct fuse_file_info
*fi
)
464 int (*__sys_open
)(const char *path
, struct fuse_file_info
*fi
);
467 __sys_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "sys_open");
470 return log_error(-1, "%s - Failed to find sys_open()", error
);
472 return __sys_open(path
, fi
);
475 static int do_sys_access(const char *path
, int mode
)
478 int (*__sys_access
)(const char *path
, int mode
);
481 __sys_access
= (int (*)(const char *, int mode
))dlsym(dlopen_handle
, "sys_access");
484 return log_error(-1, "%s - Failed to find sys_access()", error
);
486 return __sys_access(path
, mode
);
489 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
492 int (*__cg_release
)(const char *path
, struct fuse_file_info
*fi
);
495 __cg_release
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_release");
498 return log_error(-1, "%s - Failed to find cg_release()", error
);
500 return __cg_release(path
, fi
);
503 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
506 int (*__proc_release
)(const char *path
, struct fuse_file_info
*fi
);
509 __proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
512 return log_error(-1, "%s - Failed to find proc_release()", error
);
514 return __proc_release(path
, fi
);
517 static int do_sys_release(const char *path
, struct fuse_file_info
*fi
)
520 int (*__sys_release
)(const char *path
, struct fuse_file_info
*fi
);
523 __sys_release
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_release");
526 return log_error(-1, "%s - Failed to find sys_release()", error
);
528 return __sys_release(path
, fi
);
531 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
534 int (*__cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
537 __cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
))dlsym(dlopen_handle
, "cg_opendir");
540 return log_error(-1, "%s - Failed to find cg_opendir()", error
);
542 return __cg_opendir(path
, fi
);
545 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
548 int (*__cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
551 __cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "cg_releasedir");
554 return log_error(-1, "%s - Failed to find cg_releasedir()", error
);
556 return __cg_releasedir(path
, fi
);
559 static int do_sys_releasedir(const char *path
, struct fuse_file_info
*fi
)
562 int (*__sys_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
565 __sys_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*))dlsym(dlopen_handle
, "sys_releasedir");
568 return log_error(-1, "%s - Failed to find sys_releasedir()", error
);
570 return __sys_releasedir(path
, fi
);
574 static int lxcfs_getattr(const char *path
, struct stat
*sb
, struct fuse_file_info
*fi
)
576 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
582 if (strcmp(path
, "/") == 0) {
583 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
585 sb
->st_uid
= sb
->st_gid
= 0;
586 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
588 sb
->st_mode
= S_IFDIR
| 00755;
593 if (strncmp(path
, "/cgroup", 7) == 0) {
595 ret
= do_cg_getattr(path
, sb
);
600 if (strncmp(path
, "/proc", 5) == 0) {
602 ret
= do_proc_getattr(path
, sb
);
607 if (strncmp(path
, "/sys", 4) == 0) {
609 ret
= do_sys_getattr(path
, sb
);
617 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
621 if (strcmp(path
, "/") == 0)
624 if (strncmp(path
, "/cgroup", 7) == 0) {
626 ret
= do_cg_opendir(path
, fi
);
631 if (strcmp(path
, "/proc") == 0)
634 if (strncmp(path
, "/sys", 4) == 0)
641 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
642 off_t offset
, struct fuse_file_info
*fi
, enum fuse_readdir_flags flags
)
644 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
645 off_t offset
, struct fuse_file_info
*fi
)
650 if (strcmp(path
, "/") == 0) {
651 if (DIR_FILLER(filler
, buf
, ".", NULL
, 0) != 0 ||
652 DIR_FILLER(filler
, buf
, "..", NULL
, 0) != 0 ||
653 DIR_FILLER(filler
, buf
, "proc", NULL
, 0) != 0 ||
654 DIR_FILLER(filler
, buf
, "sys", NULL
, 0) != 0 ||
655 DIR_FILLER(filler
, buf
, "cgroup", NULL
, 0) != 0)
661 if (strncmp(path
, "/cgroup", 7) == 0) {
663 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
668 if (strcmp(path
, "/proc") == 0) {
670 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
675 if (strncmp(path
, "/sys", 4) == 0) {
677 ret
= do_sys_readdir(path
, buf
, filler
, offset
, fi
);
685 static int lxcfs_access(const char *path
, int mode
)
689 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
692 if (strncmp(path
, "/cgroup", 7) == 0) {
694 ret
= do_cg_access(path
, mode
);
699 if (strncmp(path
, "/proc", 5) == 0) {
701 ret
= do_proc_access(path
, mode
);
706 if (strncmp(path
, "/sys", 4) == 0) {
708 ret
= do_sys_access(path
, mode
);
716 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
720 if (strcmp(path
, "/") == 0)
723 if (strncmp(path
, "/cgroup", 7) == 0) {
725 ret
= do_cg_releasedir(path
, fi
);
730 if (strcmp(path
, "/proc") == 0)
733 if (strncmp(path
, "/sys", 4) == 0) {
735 ret
= do_sys_releasedir(path
, fi
);
743 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
747 if (strncmp(path
, "/cgroup", 7) == 0) {
749 ret
= do_cg_open(path
, fi
);
754 if (strncmp(path
, "/proc", 5) == 0) {
756 ret
= do_proc_open(path
, fi
);
761 if (strncmp(path
, "/sys", 4) == 0) {
763 ret
= do_sys_open(path
, fi
);
771 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
772 struct fuse_file_info
*fi
)
776 if (strncmp(path
, "/cgroup", 7) == 0) {
778 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
783 if (strncmp(path
, "/proc", 5) == 0) {
785 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
790 if (strncmp(path
, "/sys", 4) == 0) {
792 ret
= do_sys_read(path
, buf
, size
, offset
, fi
);
800 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
801 struct fuse_file_info
*fi
)
805 if (strncmp(path
, "/cgroup", 7) == 0) {
807 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
815 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
820 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
824 if (strncmp(path
, "/cgroup", 7) == 0) {
826 ret
= do_cg_release(path
, fi
);
831 if (strncmp(path
, "/proc", 5) == 0) {
833 ret
= do_proc_release(path
, fi
);
838 if (strncmp(path
, "/sys", 4) == 0) {
840 ret
= do_sys_release(path
, fi
);
848 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
853 int lxcfs_mkdir(const char *path
, mode_t mode
)
857 if (strncmp(path
, "/cgroup", 7) == 0) {
859 ret
= do_cg_mkdir(path
, mode
);
868 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
, struct fuse_file_info
*fi
)
870 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
875 if (strncmp(path
, "/cgroup", 7) == 0) {
877 ret
= do_cg_chown(path
, uid
, gid
);
882 if (strncmp(path
, "/proc", 5) == 0)
885 if (strncmp(path
, "/sys", 4) == 0)
892 * cat first does a truncate before doing ops->write. This doesn't
893 * really make sense for cgroups. So just return 0 always but do
897 int lxcfs_truncate(const char *path
, off_t newsize
, struct fuse_file_info
*fi
)
899 int lxcfs_truncate(const char *path
, off_t newsize
)
902 if (strncmp(path
, "/cgroup", 7) == 0)
908 int lxcfs_rmdir(const char *path
)
912 if (strncmp(path
, "/cgroup", 7) == 0) {
914 ret
= do_cg_rmdir(path
);
923 int lxcfs_chmod(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
925 int lxcfs_chmod(const char *path
, mode_t mode
)
930 if (strncmp(path
, "/cgroup", 7) == 0) {
932 ret
= do_cg_chmod(path
, mode
);
937 if (strncmp(path
, "/proc", 5) == 0)
940 if (strncmp(path
, "/sys", 4) == 0)
946 const struct fuse_operations lxcfs_ops
= {
947 .access
= lxcfs_access
,
948 .chmod
= lxcfs_chmod
,
949 .chown
= lxcfs_chown
,
950 .flush
= lxcfs_flush
,
951 .fsync
= lxcfs_fsync
,
952 .getattr
= lxcfs_getattr
,
953 .mkdir
= lxcfs_mkdir
,
955 .opendir
= lxcfs_opendir
,
957 .readdir
= lxcfs_readdir
,
958 .release
= lxcfs_release
,
959 .releasedir
= lxcfs_releasedir
,
960 .rmdir
= lxcfs_rmdir
,
961 .truncate
= lxcfs_truncate
,
962 .write
= lxcfs_write
,
993 lxcfs_info("Usage: lxcfs <directory>\n");
994 lxcfs_info("lxcfs is a FUSE-based proc, sys and cgroup virtualizing filesystem\n");
995 lxcfs_info("Options :");
996 lxcfs_info(" -d, --debug Run lxcfs with debugging enabled");
997 lxcfs_info(" -f, --foreground Run lxcfs in the foreground");
998 lxcfs_info(" -n, --help Print help");
999 lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization");
1000 lxcfs_info(" -o Options to pass directly through fuse");
1001 lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid");
1002 lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH
);
1003 lxcfs_info(" -u, --disable-swap Disable swap virtualization");
1004 lxcfs_info(" -v, --version Print lxcfs version");
1005 lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares");
1006 lxcfs_info(" --enable-pidfd Use pidfd for process tracking");
1010 static inline bool is_help(char *w
)
1012 return strcmp(w
, "-h") == 0 ||
1013 strcmp(w
, "--help") == 0 ||
1014 strcmp(w
, "-help") == 0 ||
1015 strcmp(w
, "help") == 0;
1018 static inline bool is_version(char *w
)
1020 return strcmp(w
, "-v") == 0 ||
1021 strcmp(w
, "--version") == 0 ||
1022 strcmp(w
, "-version") == 0 ||
1023 strcmp(w
, "version") == 0;
1026 static bool swallow_arg(int *argcp
, char *argv
[], char *which
)
1028 for (int i
= 1; argv
[i
]; i
++) {
1029 if (strcmp(argv
[i
], which
) != 0)
1032 for (; argv
[i
]; i
++)
1033 argv
[i
] = argv
[i
+ 1];
1042 static bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
1044 for (int i
= 1; argv
[i
]; i
++) {
1048 if (strcmp(argv
[i
], opt
) != 0)
1052 *v
= strdup(argv
[i
+ 1]);
1055 for (; argv
[i
+ 1]; i
++)
1056 argv
[i
] = argv
[i
+ 2];
1065 static int set_pidfile(char *pidfile
)
1067 __do_close
int fd
= -EBADF
;
1068 char buf
[INTTYPE_TO_STRLEN(long)];
1072 .l_whence
= SEEK_SET
,
1077 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
| O_CLOEXEC
);
1079 return log_error(-1, "Could not open pidfile %s: %m", pidfile
);
1081 if (fcntl(fd
, F_SETLK
, &fl
) < 0) {
1082 if (errno
== EAGAIN
|| errno
== EACCES
)
1083 return log_error(-1, "PID file '%s' is already locked", pidfile
);
1084 lxcfs_error("Warning; unable to lock PID file, proceeding");
1087 if (ftruncate(fd
, 0))
1088 return log_error(-1, "Error truncating PID file '%s': %m", pidfile
);
1090 ret
= snprintf(buf
, sizeof(buf
), "%ld\n", (long)getpid());
1091 if (ret
< 0 || ret
>= sizeof(buf
))
1092 return log_error(-1, "Failed to convert pid to string %m");
1094 if (write(fd
, buf
, ret
) != ret
)
1095 return log_error(-1, "Error writing to PID file '%s': %m", pidfile
);
1100 int main(int argc
, char *argv
[])
1102 int pidfile_fd
= -EBADF
;
1103 int ret
= EXIT_FAILURE
;
1104 char *pidfile
= NULL
, *saveptr
= NULL
, *token
= NULL
, *v
= NULL
;
1105 char pidfile_buf
[STRLITERALLEN(RUNTIME_PATH
) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
1106 bool debug
= false, foreground
= false;
1108 bool nonempty
= false;
1110 bool load_use
= false;
1112 * what we pass to fuse_main is:
1113 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
1115 int nargs
= 5, cnt
= 0;
1117 struct lxcfs_opts
*opts
;
1119 opts
= malloc(sizeof(struct lxcfs_opts
));
1121 lxcfs_error("Error allocating memory for options");
1124 opts
->swap_off
= false;
1125 opts
->use_pidfd
= false;
1126 opts
->use_cfs
= false;
1128 /* accomodate older init scripts */
1129 swallow_arg(&argc
, argv
, "-s");
1131 /* -f / --foreground */
1132 foreground
= swallow_arg(&argc
, argv
, "-f");
1133 if (swallow_arg(&argc
, argv
, "--foreground"))
1137 debug
= swallow_arg(&argc
, argv
, "-d");
1138 if (swallow_arg(&argc
, argv
, "--debug"))
1141 if (foreground
&& debug
)
1142 log_exit("Both --debug and --forgreound specified");
1144 /* -l / --enable-loadavg */
1145 load_use
= swallow_arg(&argc
, argv
, "-l");
1146 if (swallow_arg(&argc
, argv
, "--enable-loadavg"))
1149 /* -u / --disable-swap */
1150 opts
->swap_off
= swallow_arg(&argc
, argv
, "-u");
1151 if (swallow_arg(&argc
, argv
, "--disable-swap"))
1152 opts
->swap_off
= true;
1154 /* --enable-pidfd */
1155 opts
->use_pidfd
= swallow_arg(&argc
, argv
, "--enable-pidfd");
1158 if (swallow_arg(&argc
, argv
, "--enable-cfs"))
1159 opts
->use_cfs
= true;
1161 if (swallow_option(&argc
, argv
, "-o", &v
)) {
1162 /* Parse multiple values */
1163 for (; (token
= strtok_r(v
, ",", &saveptr
)); v
= NULL
) {
1164 if (strcmp(token
, "allow_other") == 0) {
1165 /* Noop. this is the default. Always enabled. */
1166 } else if (strcmp(token
, "nonempty") == 0) {
1168 /* FUSE3: Noop. this is the default. */
1173 lxcfs_error("Warning: unexpected fuse option %s", v
);
1182 /* -p / --pidfile */
1183 if (swallow_option(&argc
, argv
, "-p", &v
))
1185 if (!pidfile
&& swallow_option(&argc
, argv
, "--pidfile", &v
))
1188 if (argc
== 2 && is_version(argv
[1])) {
1189 lxcfs_info("%s", VERSION
);
1193 if (argc
!= 2 || is_help(argv
[1]))
1197 if (install_signal_handler(SIGUSR1
, sigusr1_reload
)) {
1198 lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno
));
1202 newargv
[cnt
++] = argv
[0];
1204 newargv
[cnt
++] = "-d";
1206 newargv
[cnt
++] = "-f";
1207 newargv
[cnt
++] = "-o";
1210 * We can't use default_permissions since we still support systems that
1211 * don't have kernels with cgroup namespace support. On such kernels
1212 * lxcfs will provide a namespaced cgroup view and needs explicit
1213 * access helpers to make that work.
1214 * Another reason that came to me is that we can't or at least
1215 * shouldn't guarantee that we don't need more complicated access
1216 * helpers for proc and sys virtualization in the future.
1219 newargv
[cnt
++] = "allow_other,entry_timeout=0.5,attr_timeout=0.5";
1222 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
1224 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
1226 newargv
[cnt
++] = argv
[1];
1227 newargv
[cnt
++] = NULL
;
1230 snprintf(pidfile_buf
, sizeof(pidfile_buf
), "%s/lxcfs.pid", RUNTIME_PATH
);
1231 pidfile
= pidfile_buf
;
1234 pidfile_fd
= set_pidfile(pidfile
);
1238 if (load_use
&& start_loadavg() != 0)
1241 if (!fuse_main(nargs
, newargv
, &lxcfs_ops
, opts
))
1249 dlclose(dlopen_handle
);
1253 close_prot_errno_disarm(pidfile_fd
);