3 * Copyright © 2014-2016 Canonical, Inc
4 * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
6 * See COPYING file for details.
9 #define FUSE_USE_VERSION 26
18 #include <linux/limits.h>
19 #include <linux/sched.h>
26 #include <sys/epoll.h>
27 #include <sys/mount.h>
28 #include <sys/socket.h>
35 #include "memory_utils.h"
39 /* Functions to keep track of number of threads using the library */
41 static int users_count
;
42 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
44 static void lock_mutex(pthread_mutex_t
*l
)
46 int ret
= pthread_mutex_lock(l
);
48 lxcfs_error("returned:%d %s\n", ret
, strerror(ret
));
53 static void unlock_mutex(pthread_mutex_t
*l
)
55 int ret
= pthread_mutex_unlock(l
);
57 lxcfs_error("returned:%d %s\n", ret
, strerror(ret
));
62 static void users_lock(void)
64 lock_mutex(&user_count_mutex
);
67 static void users_unlock(void)
69 unlock_mutex(&user_count_mutex
);
72 static pthread_t loadavg_pid
= 0;
74 /* Returns zero on success */
75 static int start_loadavg(void)
78 pthread_t (*load_daemon
)(int);
80 dlerror(); /* Clear any existing error */
82 load_daemon
= (pthread_t(*)(int))dlsym(dlopen_handle
, "load_daemon");
85 lxcfs_error("load_daemon fails:%s\n", error
);
89 loadavg_pid
= load_daemon(1);
96 /* Returns zero on success */
97 static int stop_loadavg(void)
100 int (*stop_load_daemon
)(pthread_t
);
102 stop_load_daemon
= (int (*)(pthread_t
))dlsym(dlopen_handle
, "stop_load_daemon");
105 lxcfs_error("stop_load_daemon error: %s\n", error
);
109 if (stop_load_daemon(loadavg_pid
))
115 static volatile sig_atomic_t need_reload
;
117 /* do_reload - reload the dynamic library. Done under
118 * lock and when we know the user_count was 0 */
119 static void do_reload(void)
121 char *lxcfs_lib_path
;
127 lxcfs_debug("%s\n", "Closing liblxcfs.so handle");
128 dlclose(dlopen_handle
);
131 /* First try loading using ld.so */
132 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
134 lxcfs_debug("%s\n", "Successfully called dlopen() on liblxcfs.so");
139 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
140 lxcfs_lib_path
= LIBDIR
"/lxcfs/liblxcfs.so";
142 lxcfs_lib_path
= "/usr/local/lib/lxcfs/liblxcfs.so";
144 dlopen_handle
= dlopen(lxcfs_lib_path
, RTLD_LAZY
);
145 if (!dlopen_handle
) {
146 lxcfs_error("Failed to open liblxcfs.so: %s.\n", dlerror());
155 lxcfs_error("%s\n", "lxcfs: reloaded");
160 static void up_users(void)
163 if (users_count
== 0 && need_reload
)
169 static void down_users(void)
176 static void reload_handler(int sig
)
181 /* Functions to run the library methods */
182 static int do_cg_getattr(const char *path
, struct stat
*sb
)
185 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
187 dlerror(); /* Clear any existing error */
189 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
192 lxcfs_error("%s\n", error
);
196 return cg_getattr(path
, sb
);
199 static int do_proc_getattr(const char *path
, struct stat
*sb
)
202 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
204 dlerror(); /* Clear any existing error */
206 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
209 lxcfs_error("%s\n", error
);
213 return proc_getattr(path
, sb
);
216 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
217 struct fuse_file_info
*fi
)
220 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
221 struct fuse_file_info
*fi
);
223 dlerror(); /* Clear any existing error */
225 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
228 lxcfs_error("%s\n", error
);
232 return cg_read(path
, buf
, size
, offset
, fi
);
235 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
236 struct fuse_file_info
*fi
)
239 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
240 struct fuse_file_info
*fi
);
242 dlerror(); /* Clear any existing error */
244 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
247 lxcfs_error("%s\n", error
);
251 return proc_read(path
, buf
, size
, offset
, fi
);
254 static int do_cg_write(const char *path
, const char *buf
, size_t size
,
255 off_t offset
, struct fuse_file_info
*fi
)
258 int (*cg_write
)(const char *path
, const char *buf
, size_t size
,
259 off_t offset
, struct fuse_file_info
*fi
);
261 dlerror(); /* Clear any existing error */
263 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
266 lxcfs_error("%s\n", error
);
270 return cg_write(path
, buf
, size
, offset
, fi
);
273 static int do_cg_mkdir(const char *path
, mode_t mode
)
276 int (*cg_mkdir
)(const char *path
, mode_t mode
);
278 dlerror(); /* Clear any existing error */
280 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
283 lxcfs_error("%s\n", error
);
287 return cg_mkdir(path
, mode
);
290 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
293 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
295 dlerror(); /* Clear any existing error */
297 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
300 lxcfs_error("%s\n", error
);
304 return cg_chown(path
, uid
, gid
);
307 static int do_cg_rmdir(const char *path
)
310 int (*cg_rmdir
)(const char *path
);
312 dlerror(); /* Clear any existing error */
314 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
317 lxcfs_error("%s\n", error
);
321 return cg_rmdir(path
);
324 static int do_cg_chmod(const char *path
, mode_t mode
)
327 int (*cg_chmod
)(const char *path
, mode_t mode
);
329 dlerror(); /* Clear any existing error */
331 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
334 lxcfs_error("%s\n", error
);
338 return cg_chmod(path
, mode
);
341 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
342 off_t offset
, struct fuse_file_info
*fi
)
345 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
346 off_t offset
, struct fuse_file_info
*fi
);
348 dlerror(); /* Clear any existing error */
350 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
353 lxcfs_error("%s\n", error
);
357 return cg_readdir(path
, buf
, filler
, offset
, fi
);
360 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
361 off_t offset
, struct fuse_file_info
*fi
)
364 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
,
365 off_t offset
, struct fuse_file_info
*fi
);
367 dlerror(); /* Clear any existing error */
369 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
372 lxcfs_error("%s\n", error
);
376 return proc_readdir(path
, buf
, filler
, offset
, fi
);
379 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
382 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
384 dlerror(); /* Clear any existing error */
386 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
389 lxcfs_error("%s\n", error
);
393 return cg_open(path
, fi
);
396 static int do_cg_access(const char *path
, int mode
)
399 int (*cg_access
)(const char *path
, int mode
);
401 dlerror(); /* Clear any existing error */
403 cg_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "cg_access");
406 lxcfs_error("%s\n", error
);
410 return cg_access(path
, mode
);
413 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
416 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
418 dlerror(); /* Clear any existing error */
420 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
423 lxcfs_error("%s\n", error
);
427 return proc_open(path
, fi
);
430 static int do_proc_access(const char *path
, int mode
)
433 int (*proc_access
)(const char *path
, int mode
);
435 dlerror(); /* Clear any existing error */
437 proc_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "proc_access");
440 lxcfs_error("%s\n", error
);
444 return proc_access(path
, mode
);
447 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
450 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
452 dlerror(); /* Clear any existing error */
454 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
457 lxcfs_error("%s\n", error
);
461 return cg_release(path
, fi
);
464 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
467 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
469 dlerror(); /* Clear any existing error */
471 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
474 lxcfs_error("%s\n", error
);
478 return proc_release(path
, fi
);
481 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
484 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
486 dlerror(); /* Clear any existing error */
488 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
491 lxcfs_error("%s\n", error
);
495 return cg_opendir(path
, fi
);
498 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
501 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
503 dlerror(); /* Clear any existing error */
505 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
508 lxcfs_error("%s\n", error
);
512 return cg_releasedir(path
, fi
);
517 * these just delegate to the /proc and /cgroup ops as
521 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
526 if (strcmp(path
, "/") == 0) {
527 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
530 sb
->st_uid
= sb
->st_gid
= 0;
531 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
533 sb
->st_mode
= S_IFDIR
| 00755;
538 if (strncmp(path
, "/cgroup", 7) == 0) {
540 ret
= do_cg_getattr(path
, sb
);
545 if (strncmp(path
, "/proc", 5) == 0) {
547 ret
= do_proc_getattr(path
, sb
);
555 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
557 if (strcmp(path
, "/") == 0)
560 if (strncmp(path
, "/cgroup", 7) == 0) {
563 ret
= do_cg_opendir(path
, fi
);
568 if (strcmp(path
, "/proc") == 0)
574 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
575 off_t offset
, struct fuse_file_info
*fi
)
579 if (strcmp(path
, "/") == 0) {
580 if (filler(buf
, ".", NULL
, 0) != 0 ||
581 filler(buf
, "..", NULL
, 0) != 0 ||
582 filler(buf
, "proc", NULL
, 0) != 0 ||
583 filler(buf
, "cgroup", NULL
, 0) != 0)
588 if (strncmp(path
, "/cgroup", 7) == 0) {
590 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
595 if (strcmp(path
, "/proc") == 0) {
597 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
605 static int lxcfs_access(const char *path
, int mode
)
609 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
612 if (strncmp(path
, "/cgroup", 7) == 0) {
614 ret
= do_cg_access(path
, mode
);
619 if (strncmp(path
, "/proc", 5) == 0) {
621 ret
= do_proc_access(path
, mode
);
629 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
633 if (strcmp(path
, "/") == 0)
636 if (strncmp(path
, "/cgroup", 7) == 0) {
638 ret
= do_cg_releasedir(path
, fi
);
643 if (strcmp(path
, "/proc") == 0)
649 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
653 if (strncmp(path
, "/cgroup", 7) == 0) {
655 ret
= do_cg_open(path
, fi
);
660 if (strncmp(path
, "/proc", 5) == 0) {
662 ret
= do_proc_open(path
, fi
);
670 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
671 struct fuse_file_info
*fi
)
675 if (strncmp(path
, "/cgroup", 7) == 0) {
677 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
682 if (strncmp(path
, "/proc", 5) == 0) {
684 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
692 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
693 struct fuse_file_info
*fi
)
697 if (strncmp(path
, "/cgroup", 7) == 0) {
699 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
707 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
712 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
716 if (strncmp(path
, "/cgroup", 7) == 0) {
718 ret
= do_cg_release(path
, fi
);
723 if (strncmp(path
, "/proc", 5) == 0) {
725 ret
= do_proc_release(path
, fi
);
733 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
738 int lxcfs_mkdir(const char *path
, mode_t mode
)
740 if (strncmp(path
, "/cgroup", 7) == 0) {
744 ret
= do_cg_mkdir(path
, mode
);
752 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
756 if (strncmp(path
, "/cgroup", 7) == 0) {
758 ret
= do_cg_chown(path
, uid
, gid
);
763 if (strncmp(path
, "/proc", 5) == 0)
770 * cat first does a truncate before doing ops->write. This doesn't
771 * really make sense for cgroups. So just return 0 always but do
774 int lxcfs_truncate(const char *path
, off_t newsize
)
776 if (strncmp(path
, "/cgroup", 7) == 0)
782 int lxcfs_rmdir(const char *path
)
784 if (strncmp(path
, "/cgroup", 7) == 0) {
788 ret
= do_cg_rmdir(path
);
796 int lxcfs_chmod(const char *path
, mode_t mode
)
798 if (strncmp(path
, "/cgroup", 7) == 0) {
802 ret
= do_cg_chmod(path
, mode
);
807 if (strncmp(path
, "/proc", 5) == 0)
813 const struct fuse_operations lxcfs_ops
= {
814 .getattr
= lxcfs_getattr
,
818 .mkdir
= lxcfs_mkdir
,
820 .rmdir
= lxcfs_rmdir
,
824 .chmod
= lxcfs_chmod
,
825 .chown
= lxcfs_chown
,
826 .truncate
= lxcfs_truncate
,
830 .release
= lxcfs_release
,
831 .write
= lxcfs_write
,
833 .flush
= lxcfs_flush
,
834 .fsync
= lxcfs_fsync
,
839 .opendir
= lxcfs_opendir
,
840 .readdir
= lxcfs_readdir
,
841 .releasedir
= lxcfs_releasedir
,
845 .access
= lxcfs_access
,
853 fprintf(stderr
, "Usage:\n");
854 fprintf(stderr
, "\n");
855 fprintf(stderr
, "lxcfs [-f|-d] -u -l -n [-p pidfile] mountpoint\n");
856 fprintf(stderr
, " -f running foreground by default; -d enable debug output \n");
857 fprintf(stderr
, " -l use loadavg \n");
858 fprintf(stderr
, " -u no swap \n");
859 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
860 fprintf(stderr
, "lxcfs -h\n");
864 static bool is_help(char *w
)
866 if (strcmp(w
, "-h") == 0 || strcmp(w
, "--help") == 0 ||
867 strcmp(w
, "-help") == 0 || strcmp(w
, "help") == 0)
873 bool swallow_arg(int *argcp
, char *argv
[], char *which
)
875 for (int i
= 1; argv
[i
]; i
++) {
876 if (strcmp(argv
[i
], which
) != 0)
880 argv
[i
] = argv
[i
+ 1];
890 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
894 for (i
= 1; argv
[i
]; i
++) {
898 if (strcmp(argv
[i
], opt
) != 0)
902 *v
= strdup(argv
[i
+ 1]);
905 for (; argv
[i
+ 1]; i
++)
906 argv
[i
] = argv
[i
+ 2];
916 static int set_pidfile(char *pidfile
)
918 __do_close_prot_errno
int fd
= -EBADF
;
923 fl
.l_whence
= SEEK_SET
;
927 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
929 fprintf(stderr
, "Could not open pidfile %s: %m\n", pidfile
);
933 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
934 if (errno
== EAGAIN
|| errno
== EACCES
) {
935 fprintf(stderr
, "PID file '%s' is already locked\n",
939 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
942 if (ftruncate(fd
, 0) == -1) {
943 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
947 snprintf(buf
, 50, "%ld\n", (long)getpid());
948 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
949 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
956 int main(int argc
, char *argv
[])
958 int ret
= EXIT_FAILURE
;
960 char *pidfile
= NULL
, *saveptr
= NULL
, *token
= NULL
, *v
= NULL
;
962 bool debug
= false, nonempty
= false;
963 bool load_use
= false;
965 * what we pass to fuse_main is:
966 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
968 int nargs
= 5, cnt
= 0;
971 struct lxcfs_opts
*opts
;
972 opts
= malloc(sizeof(struct lxcfs_opts
));
974 fprintf(stderr
, "Error allocating memory for options.\n");
977 opts
->swap_off
= false;
979 /* accomodate older init scripts */
980 swallow_arg(&argc
, argv
, "-s");
981 swallow_arg(&argc
, argv
, "-f");
982 debug
= swallow_arg(&argc
, argv
, "-d");
983 if (swallow_arg(&argc
, argv
, "-l"))
986 if (swallow_arg(&argc
, argv
, "-u"))
987 opts
->swap_off
= true;
989 if (swallow_option(&argc
, argv
, "-o", &v
)) {
990 /* Parse multiple values */
991 for (; (token
= strtok_r(v
, ",", &saveptr
)); v
= NULL
) {
992 if (strcmp(token
, "allow_other") == 0) {
993 /* Noop. this is the default. Always enabled. */
994 } else if (strcmp(token
, "nonempty") == 0) {
998 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
1006 if (swallow_option(&argc
, argv
, "-p", &v
))
1009 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
1010 fprintf(stderr
, "%s\n", VERSION
);
1014 if (argc
!= 2 || is_help(argv
[1]))
1018 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
1019 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
1023 newargv
[cnt
++] = argv
[0];
1025 newargv
[cnt
++] = "-d";
1027 newargv
[cnt
++] = "-f";
1028 newargv
[cnt
++] = "-o";
1030 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
1032 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
1033 newargv
[cnt
++] = argv
[1];
1034 newargv
[cnt
++] = NULL
;
1037 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
1038 pidfile
= alloca(pidfile_len
);
1039 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
1042 pidfd
= set_pidfile(pidfile
);
1046 if (load_use
&& start_loadavg() != 0)
1049 if (!fuse_main(nargs
, newargv
, &lxcfs_ops
, opts
))
1057 dlclose(dlopen_handle
);