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>
33 #include "config.h" // for VERSION
37 /* Functions to keep track of number of threads using the library */
39 static int users_count
;
40 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
41 static void lock_mutex(pthread_mutex_t
*l
)
45 if ((ret
= pthread_mutex_lock(l
)) != 0) {
46 fprintf(stderr
, "pthread_mutex_lock returned:%d %s\n", ret
, strerror(ret
));
51 static void unlock_mutex(pthread_mutex_t
*l
)
55 if ((ret
= pthread_mutex_unlock(l
)) != 0) {
56 fprintf(stderr
, "pthread_mutex_unlock returned:%d %s\n", ret
, strerror(ret
));
61 static void users_lock(void)
63 lock_mutex(&user_count_mutex
);
66 static void users_unlock(void)
68 unlock_mutex(&user_count_mutex
);
71 static volatile sig_atomic_t need_reload
;
73 /* do_reload - reload the dynamic library. Done under
74 * lock and when we know the user_count was 0 */
75 static void do_reload(void)
78 dlclose(dlopen_handle
);
80 /* First try loading using ld.so */
81 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
85 dlopen_handle
= dlopen("/usr/lib/lxcfs/liblxcfs.so", RTLD_LAZY
);
87 fprintf(stderr
, "Failed to open liblxcfs: %s.\n", dlerror());
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
)
118 /* Functions to run the library methods */
119 static int do_cg_getattr(const char *path
, struct stat
*sb
)
121 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
123 dlerror(); /* Clear any existing error */
124 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
127 fprintf(stderr
, "cg_getattr: %s\n", error
);
131 return cg_getattr(path
, sb
);
134 static int do_proc_getattr(const char *path
, struct stat
*sb
)
136 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
138 dlerror(); /* Clear any existing error */
139 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
142 fprintf(stderr
, "proc_getattr: %s\n", error
);
146 return proc_getattr(path
, sb
);
149 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
150 struct fuse_file_info
*fi
)
152 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
153 struct fuse_file_info
*fi
);
156 dlerror(); /* Clear any existing error */
157 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
160 fprintf(stderr
, "cg_read: %s\n", error
);
164 return cg_read(path
, buf
, size
, offset
, fi
);
167 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
168 struct fuse_file_info
*fi
)
170 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
171 struct fuse_file_info
*fi
);
174 dlerror(); /* Clear any existing error */
175 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
178 fprintf(stderr
, "proc_read: %s\n", error
);
182 return proc_read(path
, buf
, size
, offset
, fi
);
185 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
186 struct fuse_file_info
*fi
)
188 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
189 struct fuse_file_info
*fi
);
191 dlerror(); /* Clear any existing error */
192 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
195 fprintf(stderr
, "cg_write: %s\n", error
);
199 return cg_write(path
, buf
, size
, offset
, fi
);
202 static int do_cg_mkdir(const char *path
, mode_t mode
)
204 int (*cg_mkdir
)(const char *path
, mode_t mode
);
206 dlerror(); /* Clear any existing error */
207 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
210 fprintf(stderr
, "cg_mkdir: %s\n", error
);
214 return cg_mkdir(path
, mode
);
217 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
219 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
221 dlerror(); /* Clear any existing error */
222 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
225 fprintf(stderr
, "cg_chown: %s\n", error
);
229 return cg_chown(path
, uid
, gid
);
232 static int do_cg_rmdir(const char *path
)
234 int (*cg_rmdir
)(const char *path
);
236 dlerror(); /* Clear any existing error */
237 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
240 fprintf(stderr
, "cg_rmdir: %s\n", error
);
244 return cg_rmdir(path
);
247 static int do_cg_chmod(const char *path
, mode_t mode
)
249 int (*cg_chmod
)(const char *path
, mode_t mode
);
251 dlerror(); /* Clear any existing error */
252 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
255 fprintf(stderr
, "cg_chmod: %s\n", error
);
259 return cg_chmod(path
, mode
);
262 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
263 struct fuse_file_info
*fi
)
265 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
266 struct fuse_file_info
*fi
);
269 dlerror(); /* Clear any existing error */
270 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
273 fprintf(stderr
, "cg_readdir: %s\n", error
);
277 return cg_readdir(path
, buf
, filler
, offset
, fi
);
280 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
281 struct fuse_file_info
*fi
)
283 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
284 struct fuse_file_info
*fi
);
287 dlerror(); /* Clear any existing error */
288 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
291 fprintf(stderr
, "proc_readdir: %s\n", error
);
295 return proc_readdir(path
, buf
, filler
, offset
, fi
);
298 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
300 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
302 dlerror(); /* Clear any existing error */
303 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
306 fprintf(stderr
, "cg_open: %s\n", error
);
310 return cg_open(path
, fi
);
313 static int do_cg_access(const char *path
, int mode
)
315 int (*cg_access
)(const char *path
, int mode
);
317 dlerror(); /* Clear any existing error */
318 cg_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "cg_access");
321 fprintf(stderr
, "cg_access: %s\n", error
);
325 return cg_access(path
, mode
);
328 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
330 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
332 dlerror(); /* Clear any existing error */
333 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
336 fprintf(stderr
, "proc_open: %s\n", error
);
340 return proc_open(path
, fi
);
343 static int do_proc_access(const char *path
, int mode
)
345 int (*proc_access
)(const char *path
, int mode
);
347 dlerror(); /* Clear any existing error */
348 proc_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "proc_access");
351 fprintf(stderr
, "proc_access: %s\n", error
);
355 return proc_access(path
, mode
);
358 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
360 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
362 dlerror(); /* Clear any existing error */
363 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
366 fprintf(stderr
, "cg_release: %s\n", error
);
370 return cg_release(path
, fi
);
373 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
375 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
377 dlerror(); /* Clear any existing error */
378 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
381 fprintf(stderr
, "proc_release: %s\n", error
);
385 return proc_release(path
, fi
);
388 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
390 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
392 dlerror(); /* Clear any existing error */
393 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
396 fprintf(stderr
, "cg_opendir: %s\n", error
);
400 return cg_opendir(path
, fi
);
403 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
405 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
407 dlerror(); /* Clear any existing error */
408 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
411 fprintf(stderr
, "cg_releasedir: %s\n", error
);
415 return cg_releasedir(path
, fi
);
420 * these just delegate to the /proc and /cgroup ops as
424 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
429 if (strcmp(path
, "/") == 0) {
430 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
432 sb
->st_uid
= sb
->st_gid
= 0;
433 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
435 sb
->st_mode
= S_IFDIR
| 00755;
440 if (strncmp(path
, "/cgroup", 7) == 0) {
442 ret
= do_cg_getattr(path
, sb
);
446 if (strncmp(path
, "/proc", 5) == 0) {
448 ret
= do_proc_getattr(path
, sb
);
455 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
458 if (strcmp(path
, "/") == 0)
461 if (strncmp(path
, "/cgroup", 7) == 0) {
463 ret
= do_cg_opendir(path
, fi
);
467 if (strcmp(path
, "/proc") == 0)
472 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
473 struct fuse_file_info
*fi
)
476 if (strcmp(path
, "/") == 0) {
477 if (filler(buf
, "proc", NULL
, 0) != 0 ||
478 filler(buf
, "cgroup", NULL
, 0) != 0)
482 if (strncmp(path
, "/cgroup", 7) == 0) {
484 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
488 if (strcmp(path
, "/proc") == 0) {
490 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
497 static int lxcfs_access(const char *path
, int mode
)
501 if (strcmp(path
, "/") == 0 && access(path
, R_OK
) == 0)
504 if (strncmp(path
, "/cgroup", 7) == 0) {
506 ret
= do_cg_access(path
, mode
);
510 if (strncmp(path
, "/proc", 5) == 0) {
512 ret
= do_proc_access(path
, mode
);
520 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
523 if (strcmp(path
, "/") == 0)
525 if (strncmp(path
, "/cgroup", 7) == 0) {
527 ret
= do_cg_releasedir(path
, fi
);
531 if (strcmp(path
, "/proc") == 0)
536 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
539 if (strncmp(path
, "/cgroup", 7) == 0) {
541 ret
= do_cg_open(path
, fi
);
545 if (strncmp(path
, "/proc", 5) == 0) {
547 ret
= do_proc_open(path
, fi
);
555 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
556 struct fuse_file_info
*fi
)
559 if (strncmp(path
, "/cgroup", 7) == 0) {
561 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
565 if (strncmp(path
, "/proc", 5) == 0) {
567 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
575 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
576 struct fuse_file_info
*fi
)
579 if (strncmp(path
, "/cgroup", 7) == 0) {
581 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
589 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
594 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
597 if (strncmp(path
, "/cgroup", 7) == 0) {
599 ret
= do_cg_release(path
, fi
);
603 if (strncmp(path
, "/proc", 5) == 0) {
605 ret
= do_proc_release(path
, fi
);
613 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
618 int lxcfs_mkdir(const char *path
, mode_t mode
)
621 if (strncmp(path
, "/cgroup", 7) == 0) {
623 ret
= do_cg_mkdir(path
, mode
);
631 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
634 if (strncmp(path
, "/cgroup", 7) == 0) {
636 ret
= do_cg_chown(path
, uid
, gid
);
645 * cat first does a truncate before doing ops->write. This doesn't
646 * really make sense for cgroups. So just return 0 always but do
649 int lxcfs_truncate(const char *path
, off_t newsize
)
651 if (strncmp(path
, "/cgroup", 7) == 0)
656 int lxcfs_rmdir(const char *path
)
659 if (strncmp(path
, "/cgroup", 7) == 0) {
661 ret
= do_cg_rmdir(path
);
668 int lxcfs_chmod(const char *path
, mode_t mode
)
671 if (strncmp(path
, "/cgroup", 7) == 0) {
673 ret
= do_cg_chmod(path
, mode
);
680 const struct fuse_operations lxcfs_ops
= {
681 .getattr
= lxcfs_getattr
,
685 .mkdir
= lxcfs_mkdir
,
687 .rmdir
= lxcfs_rmdir
,
691 .chmod
= lxcfs_chmod
,
692 .chown
= lxcfs_chown
,
693 .truncate
= lxcfs_truncate
,
698 .release
= lxcfs_release
,
699 .write
= lxcfs_write
,
702 .flush
= lxcfs_flush
,
703 .fsync
= lxcfs_fsync
,
710 .opendir
= lxcfs_opendir
,
711 .readdir
= lxcfs_readdir
,
712 .releasedir
= lxcfs_releasedir
,
717 .access
= lxcfs_access
,
723 static void usage(const char *me
)
725 fprintf(stderr
, "Usage:\n");
726 fprintf(stderr
, "\n");
727 fprintf(stderr
, "%s [-p pidfile] mountpoint\n", me
);
728 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
729 fprintf(stderr
, "%s -h\n", me
);
733 static bool is_help(char *w
)
735 if (strcmp(w
, "-h") == 0 ||
736 strcmp(w
, "--help") == 0 ||
737 strcmp(w
, "-help") == 0 ||
738 strcmp(w
, "help") == 0)
743 void swallow_arg(int *argcp
, char *argv
[], char *which
)
747 for (i
= 1; argv
[i
]; i
++) {
748 if (strcmp(argv
[i
], which
) != 0)
750 for (; argv
[i
]; i
++) {
758 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
762 for (i
= 1; argv
[i
]; i
++) {
765 if (strcmp(argv
[i
], opt
) != 0)
768 *v
= strdup(argv
[i
+1]);
770 for (; argv
[i
+1]; i
++) {
779 static int set_pidfile(char *pidfile
)
786 fl
.l_whence
= SEEK_SET
;
790 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
792 fprintf(stderr
, "Could not open pidfile %s: %m", pidfile
);
796 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
797 if (errno
== EAGAIN
|| errno
== EACCES
) {
798 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
802 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
805 if (ftruncate(fd
, 0) == -1) {
806 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
811 snprintf(buf
, 50, "%ld\n", (long) getpid());
812 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
813 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
821 int main(int argc
, char *argv
[])
823 int ret
= EXIT_FAILURE
;
825 char *pidfile
= NULL
, *v
= NULL
;
828 * what we pass to fuse_main is:
829 * argv[0] -s -f -o allow_other,directio argv[1] NULL
831 int nargs
= 5, cnt
= 0;
834 /* accomodate older init scripts */
835 swallow_arg(&argc
, argv
, "-s");
836 swallow_arg(&argc
, argv
, "-f");
837 if (swallow_option(&argc
, argv
, "-o", &v
)) {
838 if (strcmp(v
, "allow_other") != 0) {
839 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
845 if (swallow_option(&argc
, argv
, "-p", &v
))
848 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
849 fprintf(stderr
, "%s\n", VERSION
);
852 if (argc
!= 2 || is_help(argv
[1]))
856 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
857 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
861 newargv
[cnt
++] = argv
[0];
862 newargv
[cnt
++] = "-f";
863 newargv
[cnt
++] = "-o";
864 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
865 newargv
[cnt
++] = argv
[1];
866 newargv
[cnt
++] = NULL
;
869 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
870 pidfile
= alloca(pidfile_len
);
871 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
873 if ((pidfd
= set_pidfile(pidfile
)) < 0)
876 if (!fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
))
881 dlclose(dlopen_handle
);