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 volatile sig_atomic_t 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
)
117 /* Functions to run the library methods */
118 static int do_cg_getattr(const char *path
, struct stat
*sb
)
120 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
122 dlerror(); /* Clear any existing error */
123 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
126 fprintf(stderr
, "cg_getattr: %s\n", error
);
130 return cg_getattr(path
, sb
);
133 static int do_proc_getattr(const char *path
, struct stat
*sb
)
135 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
137 dlerror(); /* Clear any existing error */
138 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
141 fprintf(stderr
, "proc_getattr: %s\n", error
);
145 return proc_getattr(path
, sb
);
148 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
149 struct fuse_file_info
*fi
)
151 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
152 struct fuse_file_info
*fi
);
155 dlerror(); /* Clear any existing error */
156 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
159 fprintf(stderr
, "cg_read: %s\n", error
);
163 return cg_read(path
, buf
, size
, offset
, fi
);
166 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
167 struct fuse_file_info
*fi
)
169 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
170 struct fuse_file_info
*fi
);
173 dlerror(); /* Clear any existing error */
174 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
177 fprintf(stderr
, "proc_read: %s\n", error
);
181 return proc_read(path
, buf
, size
, offset
, fi
);
184 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
185 struct fuse_file_info
*fi
)
187 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
188 struct fuse_file_info
*fi
);
190 dlerror(); /* Clear any existing error */
191 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
194 fprintf(stderr
, "cg_write: %s\n", error
);
198 return cg_write(path
, buf
, size
, offset
, fi
);
201 static int do_cg_mkdir(const char *path
, mode_t mode
)
203 int (*cg_mkdir
)(const char *path
, mode_t mode
);
205 dlerror(); /* Clear any existing error */
206 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
209 fprintf(stderr
, "cg_mkdir: %s\n", error
);
213 return cg_mkdir(path
, mode
);
216 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
218 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
220 dlerror(); /* Clear any existing error */
221 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
224 fprintf(stderr
, "cg_chown: %s\n", error
);
228 return cg_chown(path
, uid
, gid
);
231 static int do_cg_rmdir(const char *path
)
233 int (*cg_rmdir
)(const char *path
);
235 dlerror(); /* Clear any existing error */
236 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
239 fprintf(stderr
, "cg_rmdir: %s\n", error
);
243 return cg_rmdir(path
);
246 static int do_cg_chmod(const char *path
, mode_t mode
)
248 int (*cg_chmod
)(const char *path
, mode_t mode
);
250 dlerror(); /* Clear any existing error */
251 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
254 fprintf(stderr
, "cg_chmod: %s\n", error
);
258 return cg_chmod(path
, mode
);
261 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
262 struct fuse_file_info
*fi
)
264 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
265 struct fuse_file_info
*fi
);
268 dlerror(); /* Clear any existing error */
269 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
272 fprintf(stderr
, "cg_readdir: %s\n", error
);
276 return cg_readdir(path
, buf
, filler
, offset
, fi
);
279 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
280 struct fuse_file_info
*fi
)
282 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
283 struct fuse_file_info
*fi
);
286 dlerror(); /* Clear any existing error */
287 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
290 fprintf(stderr
, "proc_readdir: %s\n", error
);
294 return proc_readdir(path
, buf
, filler
, offset
, fi
);
297 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
299 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
301 dlerror(); /* Clear any existing error */
302 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
305 fprintf(stderr
, "cg_open: %s\n", error
);
309 return cg_open(path
, fi
);
312 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
314 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
316 dlerror(); /* Clear any existing error */
317 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
320 fprintf(stderr
, "proc_open: %s\n", error
);
324 return proc_open(path
, fi
);
327 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
329 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
331 dlerror(); /* Clear any existing error */
332 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
335 fprintf(stderr
, "cg_release: %s\n", error
);
339 return cg_release(path
, fi
);
342 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
344 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
346 dlerror(); /* Clear any existing error */
347 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
350 fprintf(stderr
, "proc_release: %s\n", error
);
354 return proc_release(path
, fi
);
357 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
359 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
361 dlerror(); /* Clear any existing error */
362 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
365 fprintf(stderr
, "cg_opendir: %s\n", error
);
369 return cg_opendir(path
, fi
);
372 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
374 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
376 dlerror(); /* Clear any existing error */
377 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
380 fprintf(stderr
, "cg_releasedir: %s\n", error
);
384 return cg_releasedir(path
, fi
);
389 * these just delegate to the /proc and /cgroup ops as
393 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
396 if (strcmp(path
, "/") == 0) {
397 sb
->st_mode
= S_IFDIR
| 00755;
401 if (strncmp(path
, "/cgroup", 7) == 0) {
403 ret
= do_cg_getattr(path
, sb
);
407 if (strncmp(path
, "/proc", 5) == 0) {
409 ret
= do_proc_getattr(path
, sb
);
416 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
419 if (strcmp(path
, "/") == 0)
422 if (strncmp(path
, "/cgroup", 7) == 0) {
424 ret
= do_cg_opendir(path
, fi
);
428 if (strcmp(path
, "/proc") == 0)
433 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
434 struct fuse_file_info
*fi
)
437 if (strcmp(path
, "/") == 0) {
438 if (filler(buf
, "proc", NULL
, 0) != 0 ||
439 filler(buf
, "cgroup", NULL
, 0) != 0)
443 if (strncmp(path
, "/cgroup", 7) == 0) {
445 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
449 if (strcmp(path
, "/proc") == 0) {
451 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
458 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
461 if (strcmp(path
, "/") == 0)
463 if (strncmp(path
, "/cgroup", 7) == 0) {
465 ret
= do_cg_releasedir(path
, fi
);
469 if (strcmp(path
, "/proc") == 0)
474 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
477 if (strncmp(path
, "/cgroup", 7) == 0) {
479 ret
= do_cg_open(path
, fi
);
483 if (strncmp(path
, "/proc", 5) == 0) {
485 ret
= do_proc_open(path
, fi
);
493 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
494 struct fuse_file_info
*fi
)
497 if (strncmp(path
, "/cgroup", 7) == 0) {
499 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
503 if (strncmp(path
, "/proc", 5) == 0) {
505 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
513 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
514 struct fuse_file_info
*fi
)
517 if (strncmp(path
, "/cgroup", 7) == 0) {
519 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
527 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
532 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
535 if (strncmp(path
, "/cgroup", 7) == 0) {
537 ret
= do_cg_release(path
, fi
);
541 if (strncmp(path
, "/proc", 5) == 0) {
543 ret
= do_proc_release(path
, fi
);
551 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
556 int lxcfs_mkdir(const char *path
, mode_t mode
)
559 if (strncmp(path
, "/cgroup", 7) == 0) {
561 ret
= do_cg_mkdir(path
, mode
);
569 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
572 if (strncmp(path
, "/cgroup", 7) == 0) {
574 ret
= do_cg_chown(path
, uid
, gid
);
583 * cat first does a truncate before doing ops->write. This doesn't
584 * really make sense for cgroups. So just return 0 always but do
587 int lxcfs_truncate(const char *path
, off_t newsize
)
589 if (strncmp(path
, "/cgroup", 7) == 0)
594 int lxcfs_rmdir(const char *path
)
597 if (strncmp(path
, "/cgroup", 7) == 0) {
599 ret
= do_cg_rmdir(path
);
606 int lxcfs_chmod(const char *path
, mode_t mode
)
609 if (strncmp(path
, "/cgroup", 7) == 0) {
611 ret
= do_cg_chmod(path
, mode
);
618 const struct fuse_operations lxcfs_ops
= {
619 .getattr
= lxcfs_getattr
,
623 .mkdir
= lxcfs_mkdir
,
625 .rmdir
= lxcfs_rmdir
,
629 .chmod
= lxcfs_chmod
,
630 .chown
= lxcfs_chown
,
631 .truncate
= lxcfs_truncate
,
636 .release
= lxcfs_release
,
637 .write
= lxcfs_write
,
640 .flush
= lxcfs_flush
,
641 .fsync
= lxcfs_fsync
,
648 .opendir
= lxcfs_opendir
,
649 .readdir
= lxcfs_readdir
,
650 .releasedir
= lxcfs_releasedir
,
661 static void usage(const char *me
)
663 fprintf(stderr
, "Usage:\n");
664 fprintf(stderr
, "\n");
665 fprintf(stderr
, "%s [-p pidfile] mountpoint\n", me
);
666 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
667 fprintf(stderr
, "%s -h\n", me
);
671 static bool is_help(char *w
)
673 if (strcmp(w
, "-h") == 0 ||
674 strcmp(w
, "--help") == 0 ||
675 strcmp(w
, "-help") == 0 ||
676 strcmp(w
, "help") == 0)
681 void swallow_arg(int *argcp
, char *argv
[], char *which
)
685 for (i
= 1; argv
[i
]; i
++) {
686 if (strcmp(argv
[i
], which
) != 0)
688 for (; argv
[i
]; i
++) {
696 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
700 for (i
= 1; argv
[i
]; i
++) {
703 if (strcmp(argv
[i
], opt
) != 0)
706 *v
= strdup(argv
[i
+1]);
708 for (; argv
[i
+1]; i
++) {
717 static bool mkdir_p(const char *dir
, mode_t mode
)
719 const char *tmp
= dir
;
720 const char *orig
= dir
;
724 dir
= tmp
+ strspn(tmp
, "/");
725 tmp
= dir
+ strcspn(dir
, "/");
726 makeme
= strndup(orig
, dir
- orig
);
729 if (mkdir(makeme
, mode
) && errno
!= EEXIST
) {
730 fprintf(stderr
, "failed to create directory '%s': %s",
731 makeme
, strerror(errno
));
741 static bool umount_if_mounted(void)
743 if (umount2(basedir
, MNT_DETACH
) < 0 && errno
!= EINVAL
) {
744 fprintf(stderr
, "failed to umount %s: %s\n", basedir
,
751 static bool setup_cgfs_dir(void)
753 if (!mkdir_p(basedir
, 0700)) {
754 fprintf(stderr
, "Failed to create lxcfs cgdir\n");
757 if (!umount_if_mounted()) {
758 fprintf(stderr
, "Failed to clean up old lxcfs cgdir\n");
761 if (mount("tmpfs", basedir
, "tmpfs", 0, "size=100000,mode=700") < 0) {
762 fprintf(stderr
, "Failed to mount tmpfs for private controllers\n");
768 static bool do_mount_cgroup(char *controller
)
774 len
= strlen(basedir
) + strlen(controller
) + 2;
775 target
= alloca(len
);
776 ret
= snprintf(target
, len
, "%s/%s", basedir
, controller
);
777 if (ret
< 0 || ret
>= len
)
779 if (mkdir(target
, 0755) < 0 && errno
!= EEXIST
)
781 if (mount(controller
, target
, "cgroup", 0, controller
) < 0) {
782 fprintf(stderr
, "Failed mounting cgroup %s\n", controller
);
788 static bool do_mount_cgroups(void)
795 if ((f
= fopen("/proc/self/cgroup", "r")) == NULL
) {
796 fprintf(stderr
, "Error opening /proc/self/cgroup: %s\n", strerror(errno
));
800 while (getline(&line
, &len
, f
) != -1) {
803 p
= strchr(line
, ':');
808 p2
= strrchr(p
, ':');
813 if (!do_mount_cgroup(p
))
824 static bool cgfs_setup_controllers(void)
826 if (!setup_cgfs_dir()) {
830 if (!do_mount_cgroups()) {
831 fprintf(stderr
, "Failed to set up cgroup mounts\n");
838 static int set_pidfile(char *pidfile
)
845 fl
.l_whence
= SEEK_SET
;
849 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
851 fprintf(stderr
, "Could not open pidfile %s: %m", pidfile
);
855 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
856 if (errno
== EAGAIN
|| errno
== EACCES
) {
857 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
861 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
864 if (ftruncate(fd
, 0) == -1) {
865 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
870 snprintf(buf
, 50, "%ld\n", (long) getpid());
871 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
872 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
880 int main(int argc
, char *argv
[])
883 char *pidfile
= NULL
, *v
= NULL
;
886 * what we pass to fuse_main is:
887 * argv[0] -s -f -o allow_other,directio argv[1] NULL
889 int nargs
= 5, cnt
= 0;
892 /* accomodate older init scripts */
893 swallow_arg(&argc
, argv
, "-s");
894 swallow_arg(&argc
, argv
, "-f");
895 if (swallow_option(&argc
, argv
, "-o", &v
)) {
896 if (strcmp(v
, "allow_other") != 0) {
897 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
903 if (swallow_option(&argc
, argv
, "-p", &v
))
906 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
907 fprintf(stderr
, "%s\n", VERSION
);
910 if (argc
!= 2 || is_help(argv
[1]))
914 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
915 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
919 newargv
[cnt
++] = argv
[0];
920 newargv
[cnt
++] = "-f";
921 newargv
[cnt
++] = "-o";
922 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
923 newargv
[cnt
++] = argv
[1];
924 newargv
[cnt
++] = NULL
;
926 if (!cgfs_setup_controllers())
930 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
931 pidfile
= alloca(pidfile_len
);
932 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
934 if ((pidfd
= set_pidfile(pidfile
)) < 0)
937 ret
= fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
);
939 dlclose(dlopen_handle
);