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_cg_access(const char *path
, int mode
)
314 int (*cg_access
)(const char *path
, int mode
);
316 dlerror(); /* Clear any existing error */
317 cg_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "cg_access");
320 fprintf(stderr
, "cg_access: %s\n", error
);
324 return cg_access(path
, mode
);
327 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
329 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
331 dlerror(); /* Clear any existing error */
332 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
335 fprintf(stderr
, "proc_open: %s\n", error
);
339 return proc_open(path
, fi
);
342 static int do_proc_access(const char *path
, int mode
)
344 int (*proc_access
)(const char *path
, int mode
);
346 dlerror(); /* Clear any existing error */
347 proc_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "proc_access");
350 fprintf(stderr
, "proc_access: %s\n", error
);
354 return proc_access(path
, mode
);
357 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
359 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
361 dlerror(); /* Clear any existing error */
362 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
365 fprintf(stderr
, "cg_release: %s\n", error
);
369 return cg_release(path
, fi
);
372 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
374 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
376 dlerror(); /* Clear any existing error */
377 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
380 fprintf(stderr
, "proc_release: %s\n", error
);
384 return proc_release(path
, fi
);
387 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
389 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
391 dlerror(); /* Clear any existing error */
392 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
395 fprintf(stderr
, "cg_opendir: %s\n", error
);
399 return cg_opendir(path
, fi
);
402 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
404 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
406 dlerror(); /* Clear any existing error */
407 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
410 fprintf(stderr
, "cg_releasedir: %s\n", error
);
414 return cg_releasedir(path
, fi
);
419 * these just delegate to the /proc and /cgroup ops as
423 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
426 if (strcmp(path
, "/") == 0) {
427 sb
->st_mode
= S_IFDIR
| 00755;
431 if (strncmp(path
, "/cgroup", 7) == 0) {
433 ret
= do_cg_getattr(path
, sb
);
437 if (strncmp(path
, "/proc", 5) == 0) {
439 ret
= do_proc_getattr(path
, sb
);
446 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
449 if (strcmp(path
, "/") == 0)
452 if (strncmp(path
, "/cgroup", 7) == 0) {
454 ret
= do_cg_opendir(path
, fi
);
458 if (strcmp(path
, "/proc") == 0)
463 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
464 struct fuse_file_info
*fi
)
467 if (strcmp(path
, "/") == 0) {
468 if (filler(buf
, "proc", NULL
, 0) != 0 ||
469 filler(buf
, "cgroup", NULL
, 0) != 0)
473 if (strncmp(path
, "/cgroup", 7) == 0) {
475 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
479 if (strcmp(path
, "/proc") == 0) {
481 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
488 static int lxcfs_access(const char *path
, int mode
)
491 if (strncmp(path
, "/cgroup", 7) == 0) {
493 ret
= do_cg_access(path
, mode
);
497 if (strncmp(path
, "/proc", 5) == 0) {
499 ret
= do_proc_access(path
, mode
);
507 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
510 if (strcmp(path
, "/") == 0)
512 if (strncmp(path
, "/cgroup", 7) == 0) {
514 ret
= do_cg_releasedir(path
, fi
);
518 if (strcmp(path
, "/proc") == 0)
523 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
526 if (strncmp(path
, "/cgroup", 7) == 0) {
528 ret
= do_cg_open(path
, fi
);
532 if (strncmp(path
, "/proc", 5) == 0) {
534 ret
= do_proc_open(path
, fi
);
542 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
543 struct fuse_file_info
*fi
)
546 if (strncmp(path
, "/cgroup", 7) == 0) {
548 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
552 if (strncmp(path
, "/proc", 5) == 0) {
554 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
562 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
563 struct fuse_file_info
*fi
)
566 if (strncmp(path
, "/cgroup", 7) == 0) {
568 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
576 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
581 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
584 if (strncmp(path
, "/cgroup", 7) == 0) {
586 ret
= do_cg_release(path
, fi
);
590 if (strncmp(path
, "/proc", 5) == 0) {
592 ret
= do_proc_release(path
, fi
);
600 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
605 int lxcfs_mkdir(const char *path
, mode_t mode
)
608 if (strncmp(path
, "/cgroup", 7) == 0) {
610 ret
= do_cg_mkdir(path
, mode
);
618 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
621 if (strncmp(path
, "/cgroup", 7) == 0) {
623 ret
= do_cg_chown(path
, uid
, gid
);
632 * cat first does a truncate before doing ops->write. This doesn't
633 * really make sense for cgroups. So just return 0 always but do
636 int lxcfs_truncate(const char *path
, off_t newsize
)
638 if (strncmp(path
, "/cgroup", 7) == 0)
643 int lxcfs_rmdir(const char *path
)
646 if (strncmp(path
, "/cgroup", 7) == 0) {
648 ret
= do_cg_rmdir(path
);
655 int lxcfs_chmod(const char *path
, mode_t mode
)
658 if (strncmp(path
, "/cgroup", 7) == 0) {
660 ret
= do_cg_chmod(path
, mode
);
667 const struct fuse_operations lxcfs_ops
= {
668 .getattr
= lxcfs_getattr
,
672 .mkdir
= lxcfs_mkdir
,
674 .rmdir
= lxcfs_rmdir
,
678 .chmod
= lxcfs_chmod
,
679 .chown
= lxcfs_chown
,
680 .truncate
= lxcfs_truncate
,
685 .release
= lxcfs_release
,
686 .write
= lxcfs_write
,
689 .flush
= lxcfs_flush
,
690 .fsync
= lxcfs_fsync
,
697 .opendir
= lxcfs_opendir
,
698 .readdir
= lxcfs_readdir
,
699 .releasedir
= lxcfs_releasedir
,
704 .access
= lxcfs_access
,
710 static void usage(const char *me
)
712 fprintf(stderr
, "Usage:\n");
713 fprintf(stderr
, "\n");
714 fprintf(stderr
, "%s [-p pidfile] mountpoint\n", me
);
715 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
716 fprintf(stderr
, "%s -h\n", me
);
720 static bool is_help(char *w
)
722 if (strcmp(w
, "-h") == 0 ||
723 strcmp(w
, "--help") == 0 ||
724 strcmp(w
, "-help") == 0 ||
725 strcmp(w
, "help") == 0)
730 void swallow_arg(int *argcp
, char *argv
[], char *which
)
734 for (i
= 1; argv
[i
]; i
++) {
735 if (strcmp(argv
[i
], which
) != 0)
737 for (; argv
[i
]; i
++) {
745 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
749 for (i
= 1; argv
[i
]; i
++) {
752 if (strcmp(argv
[i
], opt
) != 0)
755 *v
= strdup(argv
[i
+1]);
757 for (; argv
[i
+1]; i
++) {
766 static bool mkdir_p(const char *dir
, mode_t mode
)
768 const char *tmp
= dir
;
769 const char *orig
= dir
;
773 dir
= tmp
+ strspn(tmp
, "/");
774 tmp
= dir
+ strcspn(dir
, "/");
775 makeme
= strndup(orig
, dir
- orig
);
778 if (mkdir(makeme
, mode
) && errno
!= EEXIST
) {
779 fprintf(stderr
, "failed to create directory '%s': %s",
780 makeme
, strerror(errno
));
790 static bool umount_if_mounted(void)
792 if (umount2(basedir
, MNT_DETACH
) < 0 && errno
!= EINVAL
) {
793 fprintf(stderr
, "failed to umount %s: %s\n", basedir
,
800 static bool setup_cgfs_dir(void)
802 if (!mkdir_p(basedir
, 0700)) {
803 fprintf(stderr
, "Failed to create lxcfs cgdir\n");
806 if (!umount_if_mounted()) {
807 fprintf(stderr
, "Failed to clean up old lxcfs cgdir\n");
810 if (mount("tmpfs", basedir
, "tmpfs", 0, "size=100000,mode=700") < 0) {
811 fprintf(stderr
, "Failed to mount tmpfs for private controllers\n");
817 static bool do_mount_cgroup(char *controller
)
823 len
= strlen(basedir
) + strlen(controller
) + 2;
824 target
= alloca(len
);
825 ret
= snprintf(target
, len
, "%s/%s", basedir
, controller
);
826 if (ret
< 0 || ret
>= len
)
828 if (mkdir(target
, 0755) < 0 && errno
!= EEXIST
)
830 if (mount(controller
, target
, "cgroup", 0, controller
) < 0) {
831 fprintf(stderr
, "Failed mounting cgroup %s\n", controller
);
837 static bool do_mount_cgroups(void)
844 if ((f
= fopen("/proc/self/cgroup", "r")) == NULL
) {
845 fprintf(stderr
, "Error opening /proc/self/cgroup: %s\n", strerror(errno
));
849 while (getline(&line
, &len
, f
) != -1) {
852 p
= strchr(line
, ':');
857 p2
= strrchr(p
, ':');
862 if (!do_mount_cgroup(p
))
873 static bool cgfs_setup_controllers(void)
875 if (!setup_cgfs_dir()) {
879 if (!do_mount_cgroups()) {
880 fprintf(stderr
, "Failed to set up cgroup mounts\n");
887 static int set_pidfile(char *pidfile
)
894 fl
.l_whence
= SEEK_SET
;
898 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
900 fprintf(stderr
, "Could not open pidfile %s: %m", pidfile
);
904 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
905 if (errno
== EAGAIN
|| errno
== EACCES
) {
906 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
910 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
913 if (ftruncate(fd
, 0) == -1) {
914 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
919 snprintf(buf
, 50, "%ld\n", (long) getpid());
920 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
921 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
929 int main(int argc
, char *argv
[])
932 char *pidfile
= NULL
, *v
= NULL
;
935 * what we pass to fuse_main is:
936 * argv[0] -s -f -o allow_other,directio argv[1] NULL
938 int nargs
= 5, cnt
= 0;
941 /* accomodate older init scripts */
942 swallow_arg(&argc
, argv
, "-s");
943 swallow_arg(&argc
, argv
, "-f");
944 if (swallow_option(&argc
, argv
, "-o", &v
)) {
945 if (strcmp(v
, "allow_other") != 0) {
946 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
952 if (swallow_option(&argc
, argv
, "-p", &v
))
955 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
956 fprintf(stderr
, "%s\n", VERSION
);
959 if (argc
!= 2 || is_help(argv
[1]))
963 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
964 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
968 newargv
[cnt
++] = argv
[0];
969 newargv
[cnt
++] = "-f";
970 newargv
[cnt
++] = "-o";
971 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
972 newargv
[cnt
++] = argv
[1];
973 newargv
[cnt
++] = NULL
;
975 if (!cgfs_setup_controllers())
979 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
980 pidfile
= alloca(pidfile_len
);
981 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
983 if ((pidfd
= set_pidfile(pidfile
)) < 0)
986 ret
= fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
);
988 dlclose(dlopen_handle
);