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 lxcfs_error("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 lxcfs_error("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 lxcfs_debug("%s\n", "Closing liblxcfs.so handle.");
79 dlclose(dlopen_handle
);
82 /* First try loading using ld.so */
83 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
85 lxcfs_debug("%s\n", "Successfully called dlopen() on liblxcfs.so.");
89 dlopen_handle
= dlopen("/usr/lib/lxcfs/liblxcfs.so", RTLD_LAZY
);
91 lxcfs_error("Failed to open liblxcfs.so: %s.\n", dlerror());
97 lxcfs_error("%s\n", "lxcfs: reloaded");
101 static void up_users(void)
104 if (users_count
== 0 && need_reload
)
110 static void down_users(void)
117 static void reload_handler(int sig
)
122 /* Functions to run the library methods */
123 static int do_cg_getattr(const char *path
, struct stat
*sb
)
125 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
127 dlerror(); /* Clear any existing error */
128 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
131 lxcfs_error("%s\n", error
);
135 return cg_getattr(path
, sb
);
138 static int do_proc_getattr(const char *path
, struct stat
*sb
)
140 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
142 dlerror(); /* Clear any existing error */
143 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
146 lxcfs_error("%s\n", error
);
150 return proc_getattr(path
, sb
);
153 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
154 struct fuse_file_info
*fi
)
156 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
157 struct fuse_file_info
*fi
);
160 dlerror(); /* Clear any existing error */
161 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
164 lxcfs_error("%s\n", error
);
168 return cg_read(path
, buf
, size
, offset
, fi
);
171 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
172 struct fuse_file_info
*fi
)
174 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
175 struct fuse_file_info
*fi
);
178 dlerror(); /* Clear any existing error */
179 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
182 lxcfs_error("%s\n", error
);
186 return proc_read(path
, buf
, size
, offset
, fi
);
189 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
190 struct fuse_file_info
*fi
)
192 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
193 struct fuse_file_info
*fi
);
195 dlerror(); /* Clear any existing error */
196 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
199 lxcfs_error("%s\n", error
);
203 return cg_write(path
, buf
, size
, offset
, fi
);
206 static int do_cg_mkdir(const char *path
, mode_t mode
)
208 int (*cg_mkdir
)(const char *path
, mode_t mode
);
210 dlerror(); /* Clear any existing error */
211 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
214 lxcfs_error("%s\n", error
);
218 return cg_mkdir(path
, mode
);
221 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
223 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
225 dlerror(); /* Clear any existing error */
226 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
229 lxcfs_error("%s\n", error
);
233 return cg_chown(path
, uid
, gid
);
236 static int do_cg_rmdir(const char *path
)
238 int (*cg_rmdir
)(const char *path
);
240 dlerror(); /* Clear any existing error */
241 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
244 lxcfs_error("%s\n", error
);
248 return cg_rmdir(path
);
251 static int do_cg_chmod(const char *path
, mode_t mode
)
253 int (*cg_chmod
)(const char *path
, mode_t mode
);
255 dlerror(); /* Clear any existing error */
256 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
259 lxcfs_error("%s\n", error
);
263 return cg_chmod(path
, mode
);
266 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
267 struct fuse_file_info
*fi
)
269 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
270 struct fuse_file_info
*fi
);
273 dlerror(); /* Clear any existing error */
274 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
277 lxcfs_error("%s\n", error
);
281 return cg_readdir(path
, buf
, filler
, offset
, fi
);
284 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
285 struct fuse_file_info
*fi
)
287 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
288 struct fuse_file_info
*fi
);
291 dlerror(); /* Clear any existing error */
292 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
295 lxcfs_error("%s\n", error
);
299 return proc_readdir(path
, buf
, filler
, offset
, fi
);
302 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
304 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
306 dlerror(); /* Clear any existing error */
307 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
310 lxcfs_error("%s\n", error
);
314 return cg_open(path
, fi
);
317 static int do_cg_access(const char *path
, int mode
)
319 int (*cg_access
)(const char *path
, int mode
);
321 dlerror(); /* Clear any existing error */
322 cg_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "cg_access");
325 lxcfs_error("%s\n", error
);
329 return cg_access(path
, mode
);
332 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
334 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
336 dlerror(); /* Clear any existing error */
337 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
340 lxcfs_error("%s\n", error
);
344 return proc_open(path
, fi
);
347 static int do_proc_access(const char *path
, int mode
)
349 int (*proc_access
)(const char *path
, int mode
);
351 dlerror(); /* Clear any existing error */
352 proc_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "proc_access");
355 lxcfs_error("%s\n", error
);
359 return proc_access(path
, mode
);
362 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
364 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
366 dlerror(); /* Clear any existing error */
367 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
370 lxcfs_error("%s\n", error
);
374 return cg_release(path
, fi
);
377 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
379 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
381 dlerror(); /* Clear any existing error */
382 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
385 lxcfs_error("%s\n", error
);
389 return proc_release(path
, fi
);
392 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
394 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
396 dlerror(); /* Clear any existing error */
397 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
400 lxcfs_error("%s\n", error
);
404 return cg_opendir(path
, fi
);
407 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
409 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
411 dlerror(); /* Clear any existing error */
412 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
415 lxcfs_error("%s\n", error
);
419 return cg_releasedir(path
, fi
);
424 * these just delegate to the /proc and /cgroup ops as
428 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
433 if (strcmp(path
, "/") == 0) {
434 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
436 sb
->st_uid
= sb
->st_gid
= 0;
437 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
439 sb
->st_mode
= S_IFDIR
| 00755;
444 if (strncmp(path
, "/cgroup", 7) == 0) {
446 ret
= do_cg_getattr(path
, sb
);
450 if (strncmp(path
, "/proc", 5) == 0) {
452 ret
= do_proc_getattr(path
, sb
);
459 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
462 if (strcmp(path
, "/") == 0)
465 if (strncmp(path
, "/cgroup", 7) == 0) {
467 ret
= do_cg_opendir(path
, fi
);
471 if (strcmp(path
, "/proc") == 0)
476 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
477 struct fuse_file_info
*fi
)
480 if (strcmp(path
, "/") == 0) {
481 if (filler(buf
, ".", NULL
, 0) != 0 ||
482 filler(buf
, "..", NULL
, 0) != 0 ||
483 filler(buf
, "proc", NULL
, 0) != 0 ||
484 filler(buf
, "cgroup", NULL
, 0) != 0)
488 if (strncmp(path
, "/cgroup", 7) == 0) {
490 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
494 if (strcmp(path
, "/proc") == 0) {
496 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
503 static int lxcfs_access(const char *path
, int mode
)
507 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
510 if (strncmp(path
, "/cgroup", 7) == 0) {
512 ret
= do_cg_access(path
, mode
);
516 if (strncmp(path
, "/proc", 5) == 0) {
518 ret
= do_proc_access(path
, mode
);
526 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
529 if (strcmp(path
, "/") == 0)
531 if (strncmp(path
, "/cgroup", 7) == 0) {
533 ret
= do_cg_releasedir(path
, fi
);
537 if (strcmp(path
, "/proc") == 0)
542 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
545 if (strncmp(path
, "/cgroup", 7) == 0) {
547 ret
= do_cg_open(path
, fi
);
551 if (strncmp(path
, "/proc", 5) == 0) {
553 ret
= do_proc_open(path
, fi
);
561 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
562 struct fuse_file_info
*fi
)
565 if (strncmp(path
, "/cgroup", 7) == 0) {
567 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
571 if (strncmp(path
, "/proc", 5) == 0) {
573 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
581 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
582 struct fuse_file_info
*fi
)
585 if (strncmp(path
, "/cgroup", 7) == 0) {
587 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
595 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
600 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
603 if (strncmp(path
, "/cgroup", 7) == 0) {
605 ret
= do_cg_release(path
, fi
);
609 if (strncmp(path
, "/proc", 5) == 0) {
611 ret
= do_proc_release(path
, fi
);
619 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
624 int lxcfs_mkdir(const char *path
, mode_t mode
)
627 if (strncmp(path
, "/cgroup", 7) == 0) {
629 ret
= do_cg_mkdir(path
, mode
);
637 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
640 if (strncmp(path
, "/cgroup", 7) == 0) {
642 ret
= do_cg_chown(path
, uid
, gid
);
647 if (strncmp(path
, "/proc", 5) == 0)
654 * cat first does a truncate before doing ops->write. This doesn't
655 * really make sense for cgroups. So just return 0 always but do
658 int lxcfs_truncate(const char *path
, off_t newsize
)
660 if (strncmp(path
, "/cgroup", 7) == 0)
665 int lxcfs_rmdir(const char *path
)
668 if (strncmp(path
, "/cgroup", 7) == 0) {
670 ret
= do_cg_rmdir(path
);
677 int lxcfs_chmod(const char *path
, mode_t mode
)
680 if (strncmp(path
, "/cgroup", 7) == 0) {
682 ret
= do_cg_chmod(path
, mode
);
687 if (strncmp(path
, "/proc", 5) == 0)
693 const struct fuse_operations lxcfs_ops
= {
694 .getattr
= lxcfs_getattr
,
698 .mkdir
= lxcfs_mkdir
,
700 .rmdir
= lxcfs_rmdir
,
704 .chmod
= lxcfs_chmod
,
705 .chown
= lxcfs_chown
,
706 .truncate
= lxcfs_truncate
,
711 .release
= lxcfs_release
,
712 .write
= lxcfs_write
,
715 .flush
= lxcfs_flush
,
716 .fsync
= lxcfs_fsync
,
723 .opendir
= lxcfs_opendir
,
724 .readdir
= lxcfs_readdir
,
725 .releasedir
= lxcfs_releasedir
,
730 .access
= lxcfs_access
,
738 fprintf(stderr
, "Usage:\n");
739 fprintf(stderr
, "\n");
740 fprintf(stderr
, "lxcfs [-f|-d] [-p pidfile] mountpoint\n");
741 fprintf(stderr
, " -f running foreground by default; -d enable debug output \n");
742 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
743 fprintf(stderr
, "lxcfs -h\n");
747 static bool is_help(char *w
)
749 if (strcmp(w
, "-h") == 0 ||
750 strcmp(w
, "--help") == 0 ||
751 strcmp(w
, "-help") == 0 ||
752 strcmp(w
, "help") == 0)
757 bool swallow_arg(int *argcp
, char *argv
[], char *which
)
761 for (i
= 1; argv
[i
]; i
++) {
762 if (strcmp(argv
[i
], which
) != 0)
764 for (; argv
[i
]; i
++) {
773 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
777 for (i
= 1; argv
[i
]; i
++) {
780 if (strcmp(argv
[i
], opt
) != 0)
783 *v
= strdup(argv
[i
+1]);
785 for (; argv
[i
+1]; i
++) {
794 static int set_pidfile(char *pidfile
)
801 fl
.l_whence
= SEEK_SET
;
805 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
807 fprintf(stderr
, "Could not open pidfile %s: %m\n", pidfile
);
811 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
812 if (errno
== EAGAIN
|| errno
== EACCES
) {
813 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
817 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
820 if (ftruncate(fd
, 0) == -1) {
821 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
826 snprintf(buf
, 50, "%ld\n", (long) getpid());
827 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
828 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
836 int main(int argc
, char *argv
[])
838 int ret
= EXIT_FAILURE
;
840 char *pidfile
= NULL
, *v
= NULL
;
844 * what we pass to fuse_main is:
845 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
847 int nargs
= 5, cnt
= 0;
850 /* accomodate older init scripts */
851 swallow_arg(&argc
, argv
, "-s");
852 swallow_arg(&argc
, argv
, "-f");
853 debug
= swallow_arg(&argc
, argv
, "-d");
854 if (swallow_option(&argc
, argv
, "-o", &v
)) {
855 if (strcmp(v
, "allow_other") != 0) {
856 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
862 if (swallow_option(&argc
, argv
, "-p", &v
))
865 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
866 fprintf(stderr
, "%s\n", VERSION
);
869 if (argc
!= 2 || is_help(argv
[1]))
873 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
874 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
878 newargv
[cnt
++] = argv
[0];
880 newargv
[cnt
++] = "-d";
882 newargv
[cnt
++] = "-f";
884 newargv
[cnt
++] = "-o";
885 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
886 newargv
[cnt
++] = argv
[1];
887 newargv
[cnt
++] = NULL
;
890 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
891 pidfile
= alloca(pidfile_len
);
892 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
894 if ((pidfd
= set_pidfile(pidfile
)) < 0)
897 if (!fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
))
902 dlclose(dlopen_handle
);