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
27 #include <linux/sched.h>
28 #include <sys/epoll.h>
29 #include <sys/mount.h>
30 #include <sys/socket.h>
31 #include <linux/limits.h>
34 #include "config.h" // for VERSION
38 /* Functions to keep track of number of threads using the library */
40 static int users_count
;
41 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
42 static void lock_mutex(pthread_mutex_t
*l
)
46 if ((ret
= pthread_mutex_lock(l
)) != 0) {
47 lxcfs_error("returned:%d %s\n", ret
, strerror(ret
));
52 static void unlock_mutex(pthread_mutex_t
*l
)
56 if ((ret
= pthread_mutex_unlock(l
)) != 0) {
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 volatile sig_atomic_t need_reload
;
74 /* do_reload - reload the dynamic library. Done under
75 * lock and when we know the user_count was 0 */
76 static void do_reload(void)
78 char lxcfs_lib_path
[PATH_MAX
];
80 lxcfs_debug("%s\n", "Closing liblxcfs.so handle.");
81 dlclose(dlopen_handle
);
84 /* First try loading using ld.so */
85 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
87 lxcfs_debug("%s\n", "Successfully called dlopen() on liblxcfs.so.");
92 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
93 snprintf(lxcfs_lib_path
, PATH_MAX
, "%s/lxcfs/liblxcfs.so", LIBDIR
);
95 snprintf(lxcfs_lib_path
, PATH_MAX
, "/usr/local/lib/lxcfs/liblxcfs.so");
97 dlopen_handle
= dlopen(lxcfs_lib_path
, RTLD_LAZY
);
99 lxcfs_error("Failed to open liblxcfs.so: %s.\n", dlerror());
105 lxcfs_error("%s\n", "lxcfs: reloaded");
109 static void up_users(void)
112 if (users_count
== 0 && need_reload
)
118 static void down_users(void)
125 static void reload_handler(int sig
)
130 /* Functions to run the library methods */
131 static int do_cg_getattr(const char *path
, struct stat
*sb
)
133 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
135 dlerror(); /* Clear any existing error */
136 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
139 lxcfs_error("%s\n", error
);
143 return cg_getattr(path
, sb
);
146 static int do_proc_getattr(const char *path
, struct stat
*sb
)
148 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
150 dlerror(); /* Clear any existing error */
151 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
154 lxcfs_error("%s\n", error
);
158 return proc_getattr(path
, sb
);
161 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
162 struct fuse_file_info
*fi
)
164 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
165 struct fuse_file_info
*fi
);
168 dlerror(); /* Clear any existing error */
169 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
172 lxcfs_error("%s\n", error
);
176 return cg_read(path
, buf
, size
, offset
, fi
);
179 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
180 struct fuse_file_info
*fi
)
182 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
183 struct fuse_file_info
*fi
);
186 dlerror(); /* Clear any existing error */
187 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
190 lxcfs_error("%s\n", error
);
194 return proc_read(path
, buf
, size
, offset
, fi
);
197 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
198 struct fuse_file_info
*fi
)
200 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
201 struct fuse_file_info
*fi
);
203 dlerror(); /* Clear any existing error */
204 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
207 lxcfs_error("%s\n", error
);
211 return cg_write(path
, buf
, size
, offset
, fi
);
214 static int do_cg_mkdir(const char *path
, mode_t mode
)
216 int (*cg_mkdir
)(const char *path
, mode_t mode
);
218 dlerror(); /* Clear any existing error */
219 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
222 lxcfs_error("%s\n", error
);
226 return cg_mkdir(path
, mode
);
229 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
231 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
233 dlerror(); /* Clear any existing error */
234 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
237 lxcfs_error("%s\n", error
);
241 return cg_chown(path
, uid
, gid
);
244 static int do_cg_rmdir(const char *path
)
246 int (*cg_rmdir
)(const char *path
);
248 dlerror(); /* Clear any existing error */
249 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
252 lxcfs_error("%s\n", error
);
256 return cg_rmdir(path
);
259 static int do_cg_chmod(const char *path
, mode_t mode
)
261 int (*cg_chmod
)(const char *path
, mode_t mode
);
263 dlerror(); /* Clear any existing error */
264 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
267 lxcfs_error("%s\n", error
);
271 return cg_chmod(path
, mode
);
274 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
275 struct fuse_file_info
*fi
)
277 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
278 struct fuse_file_info
*fi
);
281 dlerror(); /* Clear any existing error */
282 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
285 lxcfs_error("%s\n", error
);
289 return cg_readdir(path
, buf
, filler
, offset
, fi
);
292 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
293 struct fuse_file_info
*fi
)
295 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
296 struct fuse_file_info
*fi
);
299 dlerror(); /* Clear any existing error */
300 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
303 lxcfs_error("%s\n", error
);
307 return proc_readdir(path
, buf
, filler
, offset
, fi
);
310 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
312 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
314 dlerror(); /* Clear any existing error */
315 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
318 lxcfs_error("%s\n", error
);
322 return cg_open(path
, fi
);
325 static int do_cg_access(const char *path
, int mode
)
327 int (*cg_access
)(const char *path
, int mode
);
329 dlerror(); /* Clear any existing error */
330 cg_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "cg_access");
333 lxcfs_error("%s\n", error
);
337 return cg_access(path
, mode
);
340 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
342 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
344 dlerror(); /* Clear any existing error */
345 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
348 lxcfs_error("%s\n", error
);
352 return proc_open(path
, fi
);
355 static int do_proc_access(const char *path
, int mode
)
357 int (*proc_access
)(const char *path
, int mode
);
359 dlerror(); /* Clear any existing error */
360 proc_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "proc_access");
363 lxcfs_error("%s\n", error
);
367 return proc_access(path
, mode
);
370 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
372 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
374 dlerror(); /* Clear any existing error */
375 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
378 lxcfs_error("%s\n", error
);
382 return cg_release(path
, fi
);
385 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
387 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
389 dlerror(); /* Clear any existing error */
390 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
393 lxcfs_error("%s\n", error
);
397 return proc_release(path
, fi
);
400 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
402 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
404 dlerror(); /* Clear any existing error */
405 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
408 lxcfs_error("%s\n", error
);
412 return cg_opendir(path
, fi
);
415 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
417 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
419 dlerror(); /* Clear any existing error */
420 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
423 lxcfs_error("%s\n", error
);
427 return cg_releasedir(path
, fi
);
432 * these just delegate to the /proc and /cgroup ops as
436 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
441 if (strcmp(path
, "/") == 0) {
442 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
444 sb
->st_uid
= sb
->st_gid
= 0;
445 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
447 sb
->st_mode
= S_IFDIR
| 00755;
452 if (strncmp(path
, "/cgroup", 7) == 0) {
454 ret
= do_cg_getattr(path
, sb
);
458 if (strncmp(path
, "/proc", 5) == 0) {
460 ret
= do_proc_getattr(path
, sb
);
467 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
470 if (strcmp(path
, "/") == 0)
473 if (strncmp(path
, "/cgroup", 7) == 0) {
475 ret
= do_cg_opendir(path
, fi
);
479 if (strcmp(path
, "/proc") == 0)
484 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
485 struct fuse_file_info
*fi
)
488 if (strcmp(path
, "/") == 0) {
489 if (filler(buf
, ".", NULL
, 0) != 0 ||
490 filler(buf
, "..", NULL
, 0) != 0 ||
491 filler(buf
, "proc", NULL
, 0) != 0 ||
492 filler(buf
, "cgroup", NULL
, 0) != 0)
496 if (strncmp(path
, "/cgroup", 7) == 0) {
498 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
502 if (strcmp(path
, "/proc") == 0) {
504 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
511 static int lxcfs_access(const char *path
, int mode
)
515 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
518 if (strncmp(path
, "/cgroup", 7) == 0) {
520 ret
= do_cg_access(path
, mode
);
524 if (strncmp(path
, "/proc", 5) == 0) {
526 ret
= do_proc_access(path
, mode
);
534 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
537 if (strcmp(path
, "/") == 0)
539 if (strncmp(path
, "/cgroup", 7) == 0) {
541 ret
= do_cg_releasedir(path
, fi
);
545 if (strcmp(path
, "/proc") == 0)
550 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
553 if (strncmp(path
, "/cgroup", 7) == 0) {
555 ret
= do_cg_open(path
, fi
);
559 if (strncmp(path
, "/proc", 5) == 0) {
561 ret
= do_proc_open(path
, fi
);
569 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
570 struct fuse_file_info
*fi
)
573 if (strncmp(path
, "/cgroup", 7) == 0) {
575 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
579 if (strncmp(path
, "/proc", 5) == 0) {
581 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
589 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
590 struct fuse_file_info
*fi
)
593 if (strncmp(path
, "/cgroup", 7) == 0) {
595 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
603 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
608 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
611 if (strncmp(path
, "/cgroup", 7) == 0) {
613 ret
= do_cg_release(path
, fi
);
617 if (strncmp(path
, "/proc", 5) == 0) {
619 ret
= do_proc_release(path
, fi
);
627 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
632 int lxcfs_mkdir(const char *path
, mode_t mode
)
635 if (strncmp(path
, "/cgroup", 7) == 0) {
637 ret
= do_cg_mkdir(path
, mode
);
645 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
648 if (strncmp(path
, "/cgroup", 7) == 0) {
650 ret
= do_cg_chown(path
, uid
, gid
);
655 if (strncmp(path
, "/proc", 5) == 0)
662 * cat first does a truncate before doing ops->write. This doesn't
663 * really make sense for cgroups. So just return 0 always but do
666 int lxcfs_truncate(const char *path
, off_t newsize
)
668 if (strncmp(path
, "/cgroup", 7) == 0)
673 int lxcfs_rmdir(const char *path
)
676 if (strncmp(path
, "/cgroup", 7) == 0) {
678 ret
= do_cg_rmdir(path
);
685 int lxcfs_chmod(const char *path
, mode_t mode
)
688 if (strncmp(path
, "/cgroup", 7) == 0) {
690 ret
= do_cg_chmod(path
, mode
);
695 if (strncmp(path
, "/proc", 5) == 0)
701 const struct fuse_operations lxcfs_ops
= {
702 .getattr
= lxcfs_getattr
,
706 .mkdir
= lxcfs_mkdir
,
708 .rmdir
= lxcfs_rmdir
,
712 .chmod
= lxcfs_chmod
,
713 .chown
= lxcfs_chown
,
714 .truncate
= lxcfs_truncate
,
719 .release
= lxcfs_release
,
720 .write
= lxcfs_write
,
723 .flush
= lxcfs_flush
,
724 .fsync
= lxcfs_fsync
,
731 .opendir
= lxcfs_opendir
,
732 .readdir
= lxcfs_readdir
,
733 .releasedir
= lxcfs_releasedir
,
738 .access
= lxcfs_access
,
746 fprintf(stderr
, "Usage:\n");
747 fprintf(stderr
, "\n");
748 fprintf(stderr
, "lxcfs [-f|-d] [-p pidfile] mountpoint\n");
749 fprintf(stderr
, " -f running foreground by default; -d enable debug output \n");
750 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
751 fprintf(stderr
, "lxcfs -h\n");
755 static bool is_help(char *w
)
757 if (strcmp(w
, "-h") == 0 ||
758 strcmp(w
, "--help") == 0 ||
759 strcmp(w
, "-help") == 0 ||
760 strcmp(w
, "help") == 0)
765 bool swallow_arg(int *argcp
, char *argv
[], char *which
)
769 for (i
= 1; argv
[i
]; i
++) {
770 if (strcmp(argv
[i
], which
) != 0)
772 for (; argv
[i
]; i
++) {
781 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
785 for (i
= 1; argv
[i
]; i
++) {
788 if (strcmp(argv
[i
], opt
) != 0)
791 *v
= strdup(argv
[i
+1]);
793 for (; argv
[i
+1]; i
++) {
802 static int set_pidfile(char *pidfile
)
809 fl
.l_whence
= SEEK_SET
;
813 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
815 fprintf(stderr
, "Could not open pidfile %s: %m\n", pidfile
);
819 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
820 if (errno
== EAGAIN
|| errno
== EACCES
) {
821 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
825 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
828 if (ftruncate(fd
, 0) == -1) {
829 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
834 snprintf(buf
, 50, "%ld\n", (long) getpid());
835 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
836 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
844 int main(int argc
, char *argv
[])
846 int ret
= EXIT_FAILURE
;
848 char *pidfile
= NULL
, *v
= NULL
;
852 * what we pass to fuse_main is:
853 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
855 int nargs
= 5, cnt
= 0;
858 /* accomodate older init scripts */
859 swallow_arg(&argc
, argv
, "-s");
860 swallow_arg(&argc
, argv
, "-f");
861 debug
= swallow_arg(&argc
, argv
, "-d");
862 if (swallow_option(&argc
, argv
, "-o", &v
)) {
863 if (strcmp(v
, "allow_other") != 0) {
864 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
870 if (swallow_option(&argc
, argv
, "-p", &v
))
873 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
874 fprintf(stderr
, "%s\n", VERSION
);
877 if (argc
!= 2 || is_help(argv
[1]))
881 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
882 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
886 newargv
[cnt
++] = argv
[0];
888 newargv
[cnt
++] = "-d";
890 newargv
[cnt
++] = "-f";
892 newargv
[cnt
++] = "-o";
893 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
894 newargv
[cnt
++] = argv
[1];
895 newargv
[cnt
++] = NULL
;
898 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
899 pidfile
= alloca(pidfile_len
);
900 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
902 if ((pidfd
= set_pidfile(pidfile
)) < 0)
905 if (!fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
))
910 dlclose(dlopen_handle
);