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 dlopen_handle
= dlopen("/usr/lib/lxcfs/liblxcfs.so", RTLD_LAZY
);
86 fprintf(stderr
, "Failed to open liblxcfs\n");
92 fprintf(stderr
, "lxcfs: reloaded\n");
96 static void up_users(void)
99 if (users_count
== 0 && need_reload
)
105 static void down_users(void)
112 static void reload_handler(int sig
)
114 fprintf(stderr
, "lxcfs: caught a SIGUSR1. Reloading\n");
120 /* Functions to run the library methods */
121 static int do_cg_getattr(const char *path
, struct stat
*sb
)
123 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
125 dlerror(); /* Clear any existing error */
126 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
129 fprintf(stderr
, "cg_getattr: %s\n", error
);
133 return cg_getattr(path
, sb
);
136 static int do_proc_getattr(const char *path
, struct stat
*sb
)
138 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
140 dlerror(); /* Clear any existing error */
141 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
144 fprintf(stderr
, "proc_getattr: %s\n", error
);
148 return proc_getattr(path
, sb
);
151 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
152 struct fuse_file_info
*fi
)
154 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
155 struct fuse_file_info
*fi
);
158 dlerror(); /* Clear any existing error */
159 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
162 fprintf(stderr
, "cg_read: %s\n", error
);
166 return cg_read(path
, buf
, size
, offset
, fi
);
169 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
170 struct fuse_file_info
*fi
)
172 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
173 struct fuse_file_info
*fi
);
176 dlerror(); /* Clear any existing error */
177 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
180 fprintf(stderr
, "proc_read: %s\n", error
);
184 return proc_read(path
, buf
, size
, offset
, fi
);
187 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
188 struct fuse_file_info
*fi
)
190 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
191 struct fuse_file_info
*fi
);
193 dlerror(); /* Clear any existing error */
194 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
197 fprintf(stderr
, "cg_write: %s\n", error
);
201 return cg_write(path
, buf
, size
, offset
, fi
);
204 static int do_cg_mkdir(const char *path
, mode_t mode
)
206 int (*cg_mkdir
)(const char *path
, mode_t mode
);
208 dlerror(); /* Clear any existing error */
209 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
212 fprintf(stderr
, "cg_mkdir: %s\n", error
);
216 return cg_mkdir(path
, mode
);
219 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
221 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
223 dlerror(); /* Clear any existing error */
224 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
227 fprintf(stderr
, "cg_chown: %s\n", error
);
231 return cg_chown(path
, uid
, gid
);
234 static int do_cg_rmdir(const char *path
)
236 int (*cg_rmdir
)(const char *path
);
238 dlerror(); /* Clear any existing error */
239 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
242 fprintf(stderr
, "cg_rmdir: %s\n", error
);
246 return cg_rmdir(path
);
249 static int do_cg_chmod(const char *path
, mode_t mode
)
251 int (*cg_chmod
)(const char *path
, mode_t mode
);
253 dlerror(); /* Clear any existing error */
254 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
257 fprintf(stderr
, "cg_chmod: %s\n", error
);
261 return cg_chmod(path
, mode
);
264 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
265 struct fuse_file_info
*fi
)
267 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
268 struct fuse_file_info
*fi
);
271 dlerror(); /* Clear any existing error */
272 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
275 fprintf(stderr
, "cg_readdir: %s\n", error
);
279 return cg_readdir(path
, buf
, filler
, offset
, fi
);
282 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
283 struct fuse_file_info
*fi
)
285 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
286 struct fuse_file_info
*fi
);
289 dlerror(); /* Clear any existing error */
290 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
293 fprintf(stderr
, "proc_readdir: %s\n", error
);
297 return proc_readdir(path
, buf
, filler
, offset
, fi
);
300 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
302 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
304 dlerror(); /* Clear any existing error */
305 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
308 fprintf(stderr
, "cg_open: %s\n", error
);
312 return cg_open(path
, fi
);
315 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
317 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
319 dlerror(); /* Clear any existing error */
320 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
323 fprintf(stderr
, "proc_open: %s\n", error
);
327 return proc_open(path
, fi
);
330 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
332 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
334 dlerror(); /* Clear any existing error */
335 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
338 fprintf(stderr
, "cg_release: %s\n", error
);
342 return cg_release(path
, fi
);
345 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
347 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
349 dlerror(); /* Clear any existing error */
350 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
353 fprintf(stderr
, "proc_release: %s\n", error
);
357 return proc_release(path
, fi
);
360 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
362 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
364 dlerror(); /* Clear any existing error */
365 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
368 fprintf(stderr
, "cg_opendir: %s\n", error
);
372 return cg_opendir(path
, fi
);
375 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
377 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
379 dlerror(); /* Clear any existing error */
380 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
383 fprintf(stderr
, "cg_releasedir: %s\n", error
);
387 return cg_releasedir(path
, fi
);
392 * these just delegate to the /proc and /cgroup ops as
396 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
399 if (strcmp(path
, "/") == 0) {
400 sb
->st_mode
= S_IFDIR
| 00755;
404 if (strncmp(path
, "/cgroup", 7) == 0) {
406 ret
= do_cg_getattr(path
, sb
);
410 if (strncmp(path
, "/proc", 5) == 0) {
412 ret
= do_proc_getattr(path
, sb
);
419 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
422 if (strcmp(path
, "/") == 0)
425 if (strncmp(path
, "/cgroup", 7) == 0) {
427 ret
= do_cg_opendir(path
, fi
);
431 if (strcmp(path
, "/proc") == 0)
436 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
437 struct fuse_file_info
*fi
)
440 if (strcmp(path
, "/") == 0) {
441 if (filler(buf
, "proc", NULL
, 0) != 0 ||
442 filler(buf
, "cgroup", NULL
, 0) != 0)
446 if (strncmp(path
, "/cgroup", 7) == 0) {
448 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
452 if (strcmp(path
, "/proc") == 0) {
454 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
461 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
464 if (strcmp(path
, "/") == 0)
466 if (strncmp(path
, "/cgroup", 7) == 0) {
468 ret
= do_cg_releasedir(path
, fi
);
472 if (strcmp(path
, "/proc") == 0)
477 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
480 if (strncmp(path
, "/cgroup", 7) == 0) {
482 ret
= do_cg_open(path
, fi
);
486 if (strncmp(path
, "/proc", 5) == 0) {
488 ret
= do_proc_open(path
, fi
);
496 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
497 struct fuse_file_info
*fi
)
500 if (strncmp(path
, "/cgroup", 7) == 0) {
502 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
506 if (strncmp(path
, "/proc", 5) == 0) {
508 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
516 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
517 struct fuse_file_info
*fi
)
520 if (strncmp(path
, "/cgroup", 7) == 0) {
522 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
530 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
535 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
538 if (strncmp(path
, "/cgroup", 7) == 0) {
540 ret
= do_cg_release(path
, fi
);
544 if (strncmp(path
, "/proc", 5) == 0) {
546 ret
= do_proc_release(path
, fi
);
554 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
559 int lxcfs_mkdir(const char *path
, mode_t mode
)
562 if (strncmp(path
, "/cgroup", 7) == 0) {
564 ret
= do_cg_mkdir(path
, mode
);
572 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
575 if (strncmp(path
, "/cgroup", 7) == 0) {
577 ret
= do_cg_chown(path
, uid
, gid
);
586 * cat first does a truncate before doing ops->write. This doesn't
587 * really make sense for cgroups. So just return 0 always but do
590 int lxcfs_truncate(const char *path
, off_t newsize
)
592 if (strncmp(path
, "/cgroup", 7) == 0)
597 int lxcfs_rmdir(const char *path
)
600 if (strncmp(path
, "/cgroup", 7) == 0) {
602 ret
= do_cg_rmdir(path
);
609 int lxcfs_chmod(const char *path
, mode_t mode
)
612 if (strncmp(path
, "/cgroup", 7) == 0) {
614 ret
= do_cg_chmod(path
, mode
);
621 const struct fuse_operations lxcfs_ops
= {
622 .getattr
= lxcfs_getattr
,
626 .mkdir
= lxcfs_mkdir
,
628 .rmdir
= lxcfs_rmdir
,
632 .chmod
= lxcfs_chmod
,
633 .chown
= lxcfs_chown
,
634 .truncate
= lxcfs_truncate
,
639 .release
= lxcfs_release
,
640 .write
= lxcfs_write
,
643 .flush
= lxcfs_flush
,
644 .fsync
= lxcfs_fsync
,
651 .opendir
= lxcfs_opendir
,
652 .readdir
= lxcfs_readdir
,
653 .releasedir
= lxcfs_releasedir
,
664 static void usage(const char *me
)
666 fprintf(stderr
, "Usage:\n");
667 fprintf(stderr
, "\n");
668 fprintf(stderr
, "%s [-p pidfile] mountpoint\n", me
);
669 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
670 fprintf(stderr
, "%s -h\n", me
);
674 static bool is_help(char *w
)
676 if (strcmp(w
, "-h") == 0 ||
677 strcmp(w
, "--help") == 0 ||
678 strcmp(w
, "-help") == 0 ||
679 strcmp(w
, "help") == 0)
684 void swallow_arg(int *argcp
, char *argv
[], char *which
)
688 for (i
= 1; argv
[i
]; i
++) {
689 if (strcmp(argv
[i
], which
) != 0)
691 for (; argv
[i
]; i
++) {
699 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
703 for (i
= 1; argv
[i
]; i
++) {
706 if (strcmp(argv
[i
], opt
) != 0)
709 *v
= strdup(argv
[i
+1]);
711 for (; argv
[i
+1]; i
++) {
720 static bool mkdir_p(const char *dir
, mode_t mode
)
722 const char *tmp
= dir
;
723 const char *orig
= dir
;
727 dir
= tmp
+ strspn(tmp
, "/");
728 tmp
= dir
+ strcspn(dir
, "/");
729 makeme
= strndup(orig
, dir
- orig
);
732 if (mkdir(makeme
, mode
) && errno
!= EEXIST
) {
733 fprintf(stderr
, "failed to create directory '%s': %s",
734 makeme
, strerror(errno
));
744 static bool umount_if_mounted(void)
746 if (umount2(basedir
, MNT_DETACH
) < 0 && errno
!= EINVAL
) {
747 fprintf(stderr
, "failed to umount %s: %s\n", basedir
,
754 static bool setup_cgfs_dir(void)
756 if (!mkdir_p(basedir
, 0700)) {
757 fprintf(stderr
, "Failed to create lxcfs cgdir\n");
760 if (!umount_if_mounted()) {
761 fprintf(stderr
, "Failed to clean up old lxcfs cgdir\n");
764 if (mount("tmpfs", basedir
, "tmpfs", 0, "size=100000,mode=700") < 0) {
765 fprintf(stderr
, "Failed to mount tmpfs for private controllers\n");
771 static bool do_mount_cgroup(char *controller
)
777 len
= strlen(basedir
) + strlen(controller
) + 2;
778 target
= alloca(len
);
779 ret
= snprintf(target
, len
, "%s/%s", basedir
, controller
);
780 if (ret
< 0 || ret
>= len
)
782 if (mkdir(target
, 0755) < 0 && errno
!= EEXIST
)
784 if (mount(controller
, target
, "cgroup", 0, controller
) < 0) {
785 fprintf(stderr
, "Failed mounting cgroup %s\n", controller
);
791 static bool do_mount_cgroups(void)
798 if ((f
= fopen("/proc/self/cgroup", "r")) == NULL
) {
799 fprintf(stderr
, "Error opening /proc/self/cgroup: %s\n", strerror(errno
));
803 while (getline(&line
, &len
, f
) != -1) {
806 p
= strchr(line
, ':');
811 p2
= strrchr(p
, ':');
816 if (!do_mount_cgroup(p
))
827 static bool cgfs_setup_controllers(void)
829 if (!setup_cgfs_dir()) {
833 if (!do_mount_cgroups()) {
834 fprintf(stderr
, "Failed to set up cgroup mounts\n");
841 static int set_pidfile(char *pidfile
)
848 fl
.l_whence
= SEEK_SET
;
852 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
854 fprintf(stderr
, "Could not open pidfile %s: %m", pidfile
);
858 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
859 if (errno
== EAGAIN
|| errno
== EACCES
) {
860 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
864 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
867 if (ftruncate(fd
, 0) == -1) {
868 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
873 snprintf(buf
, 50, "%ld\n", (long) getpid());
874 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
875 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
883 int main(int argc
, char *argv
[])
886 char *pidfile
= NULL
, *v
= NULL
;
889 * what we pass to fuse_main is:
890 * argv[0] -s -f -o allow_other,directio argv[1] NULL
892 int nargs
= 5, cnt
= 0;
895 /* accomodate older init scripts */
896 swallow_arg(&argc
, argv
, "-s");
897 swallow_arg(&argc
, argv
, "-f");
898 if (swallow_option(&argc
, argv
, "-o", &v
)) {
899 if (strcmp(v
, "allow_other") != 0) {
900 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
906 if (swallow_option(&argc
, argv
, "-p", &v
))
909 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
910 fprintf(stderr
, "%s\n", VERSION
);
913 if (argc
!= 2 || is_help(argv
[1]))
917 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
918 fprintf(stderr
, "Error loading USR1 signal handler: %m\n");
922 newargv
[cnt
++] = argv
[0];
923 newargv
[cnt
++] = "-f";
924 newargv
[cnt
++] = "-o";
925 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
926 newargv
[cnt
++] = argv
[1];
927 newargv
[cnt
++] = NULL
;
929 if (!cgfs_setup_controllers())
933 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
934 pidfile
= alloca(pidfile_len
);
935 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
937 if ((pidfd
= set_pidfile(pidfile
)) < 0)
940 ret
= fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
);
942 dlclose(dlopen_handle
);