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
25 #include <linux/sched.h>
26 #include <sys/socket.h>
27 #include <sys/mount.h>
28 #include <sys/epoll.h>
31 #include "config.h" // for VERSION
36 /* Functions to keep track of number of threads using the library */
38 static int users_count
;
39 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
40 static void lock_mutex(pthread_mutex_t
*l
)
44 if ((ret
= pthread_mutex_lock(l
)) != 0) {
45 fprintf(stderr
, "pthread_mutex_lock returned:%d %s\n", ret
, strerror(ret
));
50 static void unlock_mutex(pthread_mutex_t
*l
)
54 if ((ret
= pthread_mutex_unlock(l
)) != 0) {
55 fprintf(stderr
, "pthread_mutex_unlock returned:%d %s\n", ret
, strerror(ret
));
60 static void users_lock(void)
62 lock_mutex(&user_count_mutex
);
65 static void users_unlock(void)
67 unlock_mutex(&user_count_mutex
);
70 static int need_reload
;
72 /* do_reload - reload the dynamic library. Done under
73 * lock and when we know the user_count was 0 */
74 static void do_reload(void)
77 dlclose(dlopen_handle
);
79 /* First try loading using ld.so */
80 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
84 /* Fall back to loading from /usr/lib/lxcfs/liblxcfs.so */
85 dlopen_handle
= dlopen(LIBDIR
"lxcfs/liblxcfs.so", RTLD_LAZY
);
87 fprintf(stderr
, "Failed to open liblxcfs\n");
93 fprintf(stderr
, "lxcfs: reloaded\n");
97 static void up_users(void)
100 if (users_count
== 0 && need_reload
)
106 static void down_users(void)
113 static void reload_handler(int sig
)
115 fprintf(stderr
, "lxcfs: caught a SIGUSR1. Reloading\n");
121 /* Functions to run the library methods */
122 static int do_cg_getattr(const char *path
, struct stat
*sb
)
124 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
126 dlerror(); /* Clear any existing error */
127 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
130 fprintf(stderr
, "cg_getattr: %s\n", error
);
134 return cg_getattr(path
, sb
);
137 static int do_proc_getattr(const char *path
, struct stat
*sb
)
139 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
141 dlerror(); /* Clear any existing error */
142 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
145 fprintf(stderr
, "proc_getattr: %s\n", error
);
149 return proc_getattr(path
, sb
);
152 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
153 struct fuse_file_info
*fi
)
155 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
156 struct fuse_file_info
*fi
);
159 dlerror(); /* Clear any existing error */
160 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
163 fprintf(stderr
, "cg_read: %s\n", error
);
167 return cg_read(path
, buf
, size
, offset
, fi
);
170 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
171 struct fuse_file_info
*fi
)
173 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
174 struct fuse_file_info
*fi
);
177 dlerror(); /* Clear any existing error */
178 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
181 fprintf(stderr
, "proc_read: %s\n", error
);
185 return proc_read(path
, buf
, size
, offset
, fi
);
188 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
189 struct fuse_file_info
*fi
)
191 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
192 struct fuse_file_info
*fi
);
194 dlerror(); /* Clear any existing error */
195 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
198 fprintf(stderr
, "cg_write: %s\n", error
);
202 return cg_write(path
, buf
, size
, offset
, fi
);
205 static int do_cg_mkdir(const char *path
, mode_t mode
)
207 int (*cg_mkdir
)(const char *path
, mode_t mode
);
209 dlerror(); /* Clear any existing error */
210 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
213 fprintf(stderr
, "cg_mkdir: %s\n", error
);
217 return cg_mkdir(path
, mode
);
220 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
222 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
224 dlerror(); /* Clear any existing error */
225 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
228 fprintf(stderr
, "cg_chown: %s\n", error
);
232 return cg_chown(path
, uid
, gid
);
235 static int do_cg_rmdir(const char *path
)
237 int (*cg_rmdir
)(const char *path
);
239 dlerror(); /* Clear any existing error */
240 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
243 fprintf(stderr
, "cg_rmdir: %s\n", error
);
247 return cg_rmdir(path
);
250 static int do_cg_chmod(const char *path
, mode_t mode
)
252 int (*cg_chmod
)(const char *path
, mode_t mode
);
254 dlerror(); /* Clear any existing error */
255 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
258 fprintf(stderr
, "cg_chmod: %s\n", error
);
262 return cg_chmod(path
, mode
);
265 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
266 struct fuse_file_info
*fi
)
268 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
269 struct fuse_file_info
*fi
);
272 dlerror(); /* Clear any existing error */
273 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
276 fprintf(stderr
, "cg_readdir: %s\n", error
);
280 return cg_readdir(path
, buf
, filler
, offset
, fi
);
283 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
284 struct fuse_file_info
*fi
)
286 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
287 struct fuse_file_info
*fi
);
290 dlerror(); /* Clear any existing error */
291 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
294 fprintf(stderr
, "proc_readdir: %s\n", error
);
298 return proc_readdir(path
, buf
, filler
, offset
, fi
);
301 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
303 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
305 dlerror(); /* Clear any existing error */
306 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
309 fprintf(stderr
, "cg_open: %s\n", error
);
313 return cg_open(path
, fi
);
316 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
318 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
320 dlerror(); /* Clear any existing error */
321 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
324 fprintf(stderr
, "proc_open: %s\n", error
);
328 return proc_open(path
, fi
);
331 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
333 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
335 dlerror(); /* Clear any existing error */
336 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
339 fprintf(stderr
, "cg_release: %s\n", error
);
343 return cg_release(path
, fi
);
346 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
348 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
350 dlerror(); /* Clear any existing error */
351 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
354 fprintf(stderr
, "proc_release: %s\n", error
);
358 return proc_release(path
, fi
);
361 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
363 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
365 dlerror(); /* Clear any existing error */
366 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
369 fprintf(stderr
, "cg_opendir: %s\n", error
);
373 return cg_opendir(path
, fi
);
376 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
378 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
380 dlerror(); /* Clear any existing error */
381 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
384 fprintf(stderr
, "cg_releasedir: %s\n", error
);
388 return cg_releasedir(path
, fi
);
393 * these just delegate to the /proc and /cgroup ops as
397 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
400 if (strcmp(path
, "/") == 0) {
401 sb
->st_mode
= S_IFDIR
| 00755;
405 if (strncmp(path
, "/cgroup", 7) == 0) {
407 ret
= do_cg_getattr(path
, sb
);
411 if (strncmp(path
, "/proc", 5) == 0) {
413 ret
= do_proc_getattr(path
, sb
);
420 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
423 if (strcmp(path
, "/") == 0)
426 if (strncmp(path
, "/cgroup", 7) == 0) {
428 ret
= do_cg_opendir(path
, fi
);
432 if (strcmp(path
, "/proc") == 0)
437 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
438 struct fuse_file_info
*fi
)
441 if (strcmp(path
, "/") == 0) {
442 if (filler(buf
, "proc", NULL
, 0) != 0 ||
443 filler(buf
, "cgroup", NULL
, 0) != 0)
447 if (strncmp(path
, "/cgroup", 7) == 0) {
449 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
453 if (strcmp(path
, "/proc") == 0) {
455 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
462 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
465 if (strcmp(path
, "/") == 0)
467 if (strncmp(path
, "/cgroup", 7) == 0) {
469 ret
= do_cg_releasedir(path
, fi
);
473 if (strcmp(path
, "/proc") == 0)
478 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
481 if (strncmp(path
, "/cgroup", 7) == 0) {
483 ret
= do_cg_open(path
, fi
);
487 if (strncmp(path
, "/proc", 5) == 0) {
489 ret
= do_proc_open(path
, fi
);
497 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
498 struct fuse_file_info
*fi
)
501 if (strncmp(path
, "/cgroup", 7) == 0) {
503 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
507 if (strncmp(path
, "/proc", 5) == 0) {
509 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
517 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
518 struct fuse_file_info
*fi
)
521 if (strncmp(path
, "/cgroup", 7) == 0) {
523 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
531 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
536 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
539 if (strncmp(path
, "/cgroup", 7) == 0) {
541 ret
= do_cg_release(path
, fi
);
545 if (strncmp(path
, "/proc", 5) == 0) {
547 ret
= do_proc_release(path
, fi
);
555 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
560 int lxcfs_mkdir(const char *path
, mode_t mode
)
563 if (strncmp(path
, "/cgroup", 7) == 0) {
565 ret
= do_cg_mkdir(path
, mode
);
573 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
576 if (strncmp(path
, "/cgroup", 7) == 0) {
578 ret
= do_cg_chown(path
, uid
, gid
);
587 * cat first does a truncate before doing ops->write. This doesn't
588 * really make sense for cgroups. So just return 0 always but do
591 int lxcfs_truncate(const char *path
, off_t newsize
)
593 if (strncmp(path
, "/cgroup", 7) == 0)
598 int lxcfs_rmdir(const char *path
)
601 if (strncmp(path
, "/cgroup", 7) == 0) {
603 ret
= do_cg_rmdir(path
);
610 int lxcfs_chmod(const char *path
, mode_t mode
)
613 if (strncmp(path
, "/cgroup", 7) == 0) {
615 ret
= do_cg_chmod(path
, mode
);
622 const struct fuse_operations lxcfs_ops
= {
623 .getattr
= lxcfs_getattr
,
627 .mkdir
= lxcfs_mkdir
,
629 .rmdir
= lxcfs_rmdir
,
633 .chmod
= lxcfs_chmod
,
634 .chown
= lxcfs_chown
,
635 .truncate
= lxcfs_truncate
,
640 .release
= lxcfs_release
,
641 .write
= lxcfs_write
,
644 .flush
= lxcfs_flush
,
645 .fsync
= lxcfs_fsync
,
652 .opendir
= lxcfs_opendir
,
653 .readdir
= lxcfs_readdir
,
654 .releasedir
= lxcfs_releasedir
,
665 static void usage(const char *me
)
667 fprintf(stderr
, "Usage:\n");
668 fprintf(stderr
, "\n");
669 fprintf(stderr
, "%s [-p pidfile] mountpoint\n", me
);
670 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
671 fprintf(stderr
, "%s -h\n", me
);
675 static bool is_help(char *w
)
677 if (strcmp(w
, "-h") == 0 ||
678 strcmp(w
, "--help") == 0 ||
679 strcmp(w
, "-help") == 0 ||
680 strcmp(w
, "help") == 0)
685 void swallow_arg(int *argcp
, char *argv
[], char *which
)
689 for (i
= 1; argv
[i
]; i
++) {
690 if (strcmp(argv
[i
], which
) != 0)
692 for (; argv
[i
]; i
++) {
700 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
704 for (i
= 1; argv
[i
]; i
++) {
707 if (strcmp(argv
[i
], opt
) != 0)
710 *v
= strdup(argv
[i
+1]);
712 for (; argv
[i
+1]; i
++) {
721 static bool mkdir_p(const char *dir
, mode_t mode
)
723 const char *tmp
= dir
;
724 const char *orig
= dir
;
728 dir
= tmp
+ strspn(tmp
, "/");
729 tmp
= dir
+ strcspn(dir
, "/");
730 makeme
= strndup(orig
, dir
- orig
);
733 if (mkdir(makeme
, mode
) && errno
!= EEXIST
) {
734 fprintf(stderr
, "failed to create directory '%s': %s",
735 makeme
, strerror(errno
));
745 static bool umount_if_mounted(void)
747 if (umount2(basedir
, MNT_DETACH
) < 0 && errno
!= EINVAL
) {
748 fprintf(stderr
, "failed to umount %s: %s\n", basedir
,
755 static bool setup_cgfs_dir(void)
757 if (!mkdir_p(basedir
, 0700)) {
758 fprintf(stderr
, "Failed to create lxcfs cgdir\n");
761 if (!umount_if_mounted()) {
762 fprintf(stderr
, "Failed to clean up old lxcfs cgdir\n");
765 if (mount("tmpfs", basedir
, "tmpfs", 0, "size=100000,mode=700") < 0) {
766 fprintf(stderr
, "Failed to mount tmpfs for private controllers\n");
772 static bool do_mount_cgroup(char *controller
)
778 len
= strlen(basedir
) + strlen(controller
) + 2;
779 target
= alloca(len
);
780 ret
= snprintf(target
, len
, "%s/%s", basedir
, controller
);
781 if (ret
< 0 || ret
>= len
)
783 if (mkdir(target
, 0755) < 0 && errno
!= EEXIST
)
785 if (mount(controller
, target
, "cgroup", 0, controller
) < 0) {
786 fprintf(stderr
, "Failed mounting cgroup %s\n", controller
);
792 static bool do_mount_cgroups(void)
799 if ((f
= fopen("/proc/self/cgroup", "r")) == NULL
) {
800 fprintf(stderr
, "Error opening /proc/self/cgroup: %s\n", strerror(errno
));
804 while (getline(&line
, &len
, f
) != -1) {
807 p
= strchr(line
, ':');
812 p2
= strrchr(p
, ':');
817 if (!do_mount_cgroup(p
))
828 static bool cgfs_setup_controllers(void)
830 if (!setup_cgfs_dir()) {
834 if (!do_mount_cgroups()) {
835 fprintf(stderr
, "Failed to set up cgroup mounts\n");
842 static int set_pidfile(char *pidfile
)
849 fl
.l_whence
= SEEK_SET
;
853 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
855 fprintf(stderr
, "Could not open pidfile %s: %m", pidfile
);
859 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
860 if (errno
== EAGAIN
|| errno
== EACCES
) {
861 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
865 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
868 if (ftruncate(fd
, 0) == -1) {
869 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
874 snprintf(buf
, 50, "%ld\n", (long) getpid());
875 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
876 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
884 int main(int argc
, char *argv
[])
887 char *pidfile
= NULL
, *v
= NULL
;
890 * what we pass to fuse_main is:
891 * argv[0] -s -f -o allow_other,directio argv[1] NULL
893 int nargs
= 5, cnt
= 0;
896 /* accomodate older init scripts */
897 swallow_arg(&argc
, argv
, "-s");
898 swallow_arg(&argc
, argv
, "-f");
899 if (swallow_option(&argc
, argv
, "-o", &v
)) {
900 if (strcmp(v
, "allow_other") != 0) {
901 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
907 if (swallow_option(&argc
, argv
, "-p", &v
))
910 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
911 fprintf(stderr
, "%s\n", VERSION
);
914 if (argc
!= 2 || is_help(argv
[1]))
918 signal(SIGUSR1
, reload_handler
);
920 newargv
[cnt
++] = argv
[0];
921 newargv
[cnt
++] = "-f";
922 newargv
[cnt
++] = "-o";
923 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
924 newargv
[cnt
++] = argv
[1];
925 newargv
[cnt
++] = NULL
;
927 if (!cgfs_setup_controllers())
931 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
932 pidfile
= alloca(pidfile_len
);
933 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
935 if ((pidfd
= set_pidfile(pidfile
)) < 0)
938 ret
= fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
);
940 dlclose(dlopen_handle
);