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>
31 #include <linux/limits.h>
34 #include "config.h" // for VERSION
38 /* Functions to keep track of number of threads using the library */
40 static int users_count
;
41 static pthread_mutex_t user_count_mutex
= PTHREAD_MUTEX_INITIALIZER
;
42 static void lock_mutex(pthread_mutex_t
*l
)
46 if ((ret
= pthread_mutex_lock(l
)) != 0) {
47 lxcfs_error("returned:%d %s\n", ret
, strerror(ret
));
52 static void unlock_mutex(pthread_mutex_t
*l
)
56 if ((ret
= pthread_mutex_unlock(l
)) != 0) {
57 lxcfs_error("returned:%d %s\n", ret
, strerror(ret
));
62 static void users_lock(void)
64 lock_mutex(&user_count_mutex
);
67 static void users_unlock(void)
69 unlock_mutex(&user_count_mutex
);
72 static pthread_t loadavg_pid
= 0;
74 /* Returns zero on success */
75 static int start_loadavg(void) {
77 pthread_t (*load_daemon
)(int);
79 dlerror(); /* Clear any existing error */
81 load_daemon
= (pthread_t (*)(int)) dlsym(dlopen_handle
, "load_daemon");
84 lxcfs_error("load_daemon fails:%s\n", error
);
87 loadavg_pid
= load_daemon(1);
94 /* Returns zero on success */
95 static int stop_loadavg(void) {
97 int (*stop_load_daemon
)(pthread_t
);
99 stop_load_daemon
= (int (*)(pthread_t
)) dlsym(dlopen_handle
, "stop_load_daemon");
102 lxcfs_error("stop_load_daemon error: %s\n", error
);
106 if (stop_load_daemon(loadavg_pid
) != 0)
112 static volatile sig_atomic_t need_reload
;
114 /* do_reload - reload the dynamic library. Done under
115 * lock and when we know the user_count was 0 */
116 static void do_reload(void)
118 char lxcfs_lib_path
[PATH_MAX
];
124 lxcfs_debug("%s\n", "Closing liblxcfs.so handle.");
125 dlclose(dlopen_handle
);
128 /* First try loading using ld.so */
129 dlopen_handle
= dlopen("liblxcfs.so", RTLD_LAZY
);
131 lxcfs_debug("%s\n", "Successfully called dlopen() on liblxcfs.so.");
136 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
137 snprintf(lxcfs_lib_path
, PATH_MAX
, "%s/lxcfs/liblxcfs.so", LIBDIR
);
139 snprintf(lxcfs_lib_path
, PATH_MAX
, "/usr/local/lib/lxcfs/liblxcfs.so");
141 dlopen_handle
= dlopen(lxcfs_lib_path
, RTLD_LAZY
);
142 if (!dlopen_handle
) {
143 lxcfs_error("Failed to open liblxcfs.so: %s.\n", dlerror());
152 lxcfs_error("%s\n", "lxcfs: reloaded");
156 static void up_users(void)
159 if (users_count
== 0 && need_reload
)
165 static void down_users(void)
172 static void reload_handler(int sig
)
177 /* Functions to run the library methods */
178 static int do_cg_getattr(const char *path
, struct stat
*sb
)
180 int (*cg_getattr
)(const char *path
, struct stat
*sb
);
182 dlerror(); /* Clear any existing error */
183 cg_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "cg_getattr");
186 lxcfs_error("%s\n", error
);
190 return cg_getattr(path
, sb
);
193 static int do_proc_getattr(const char *path
, struct stat
*sb
)
195 int (*proc_getattr
)(const char *path
, struct stat
*sb
);
197 dlerror(); /* Clear any existing error */
198 proc_getattr
= (int (*)(const char *, struct stat
*)) dlsym(dlopen_handle
, "proc_getattr");
201 lxcfs_error("%s\n", error
);
205 return proc_getattr(path
, sb
);
208 static int do_cg_read(const char *path
, char *buf
, size_t size
, off_t offset
,
209 struct fuse_file_info
*fi
)
211 int (*cg_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
212 struct fuse_file_info
*fi
);
215 dlerror(); /* Clear any existing error */
216 cg_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_read");
219 lxcfs_error("%s\n", error
);
223 return cg_read(path
, buf
, size
, offset
, fi
);
226 static int do_proc_read(const char *path
, char *buf
, size_t size
, off_t offset
,
227 struct fuse_file_info
*fi
)
229 int (*proc_read
)(const char *path
, char *buf
, size_t size
, off_t offset
,
230 struct fuse_file_info
*fi
);
233 dlerror(); /* Clear any existing error */
234 proc_read
= (int (*)(const char *, char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_read");
237 lxcfs_error("%s\n", error
);
241 return proc_read(path
, buf
, size
, offset
, fi
);
244 static int do_cg_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
245 struct fuse_file_info
*fi
)
247 int (*cg_write
)(const char *path
, const char *buf
, size_t size
, off_t offset
,
248 struct fuse_file_info
*fi
);
250 dlerror(); /* Clear any existing error */
251 cg_write
= (int (*)(const char *, const char *, size_t, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_write");
254 lxcfs_error("%s\n", error
);
258 return cg_write(path
, buf
, size
, offset
, fi
);
261 static int do_cg_mkdir(const char *path
, mode_t mode
)
263 int (*cg_mkdir
)(const char *path
, mode_t mode
);
265 dlerror(); /* Clear any existing error */
266 cg_mkdir
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_mkdir");
269 lxcfs_error("%s\n", error
);
273 return cg_mkdir(path
, mode
);
276 static int do_cg_chown(const char *path
, uid_t uid
, gid_t gid
)
278 int (*cg_chown
)(const char *path
, uid_t uid
, gid_t gid
);
280 dlerror(); /* Clear any existing error */
281 cg_chown
= (int (*)(const char *, uid_t
, gid_t
)) dlsym(dlopen_handle
, "cg_chown");
284 lxcfs_error("%s\n", error
);
288 return cg_chown(path
, uid
, gid
);
291 static int do_cg_rmdir(const char *path
)
293 int (*cg_rmdir
)(const char *path
);
295 dlerror(); /* Clear any existing error */
296 cg_rmdir
= (int (*)(const char *path
)) dlsym(dlopen_handle
, "cg_rmdir");
299 lxcfs_error("%s\n", error
);
303 return cg_rmdir(path
);
306 static int do_cg_chmod(const char *path
, mode_t mode
)
308 int (*cg_chmod
)(const char *path
, mode_t mode
);
310 dlerror(); /* Clear any existing error */
311 cg_chmod
= (int (*)(const char *, mode_t
)) dlsym(dlopen_handle
, "cg_chmod");
314 lxcfs_error("%s\n", error
);
318 return cg_chmod(path
, mode
);
321 static int do_cg_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
322 struct fuse_file_info
*fi
)
324 int (*cg_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
325 struct fuse_file_info
*fi
);
328 dlerror(); /* Clear any existing error */
329 cg_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_readdir");
332 lxcfs_error("%s\n", error
);
336 return cg_readdir(path
, buf
, filler
, offset
, fi
);
339 static int do_proc_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
340 struct fuse_file_info
*fi
)
342 int (*proc_readdir
)(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
343 struct fuse_file_info
*fi
);
346 dlerror(); /* Clear any existing error */
347 proc_readdir
= (int (*)(const char *, void *, fuse_fill_dir_t
, off_t
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_readdir");
350 lxcfs_error("%s\n", error
);
354 return proc_readdir(path
, buf
, filler
, offset
, fi
);
357 static int do_cg_open(const char *path
, struct fuse_file_info
*fi
)
359 int (*cg_open
)(const char *path
, struct fuse_file_info
*fi
);
361 dlerror(); /* Clear any existing error */
362 cg_open
= (int (*)(const char *, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_open");
365 lxcfs_error("%s\n", error
);
369 return cg_open(path
, fi
);
372 static int do_cg_access(const char *path
, int mode
)
374 int (*cg_access
)(const char *path
, int mode
);
376 dlerror(); /* Clear any existing error */
377 cg_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "cg_access");
380 lxcfs_error("%s\n", error
);
384 return cg_access(path
, mode
);
387 static int do_proc_open(const char *path
, struct fuse_file_info
*fi
)
389 int (*proc_open
)(const char *path
, struct fuse_file_info
*fi
);
391 dlerror(); /* Clear any existing error */
392 proc_open
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "proc_open");
395 lxcfs_error("%s\n", error
);
399 return proc_open(path
, fi
);
402 static int do_proc_access(const char *path
, int mode
)
404 int (*proc_access
)(const char *path
, int mode
);
406 dlerror(); /* Clear any existing error */
407 proc_access
= (int (*)(const char *, int mode
)) dlsym(dlopen_handle
, "proc_access");
410 lxcfs_error("%s\n", error
);
414 return proc_access(path
, mode
);
417 static int do_cg_release(const char *path
, struct fuse_file_info
*fi
)
419 int (*cg_release
)(const char *path
, struct fuse_file_info
*fi
);
421 dlerror(); /* Clear any existing error */
422 cg_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_release");
425 lxcfs_error("%s\n", error
);
429 return cg_release(path
, fi
);
432 static int do_proc_release(const char *path
, struct fuse_file_info
*fi
)
434 int (*proc_release
)(const char *path
, struct fuse_file_info
*fi
);
436 dlerror(); /* Clear any existing error */
437 proc_release
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "proc_release");
440 lxcfs_error("%s\n", error
);
444 return proc_release(path
, fi
);
447 static int do_cg_opendir(const char *path
, struct fuse_file_info
*fi
)
449 int (*cg_opendir
)(const char *path
, struct fuse_file_info
*fi
);
451 dlerror(); /* Clear any existing error */
452 cg_opendir
= (int (*)(const char *path
, struct fuse_file_info
*fi
)) dlsym(dlopen_handle
, "cg_opendir");
455 lxcfs_error("%s\n", error
);
459 return cg_opendir(path
, fi
);
462 static int do_cg_releasedir(const char *path
, struct fuse_file_info
*fi
)
464 int (*cg_releasedir
)(const char *path
, struct fuse_file_info
*fi
);
466 dlerror(); /* Clear any existing error */
467 cg_releasedir
= (int (*)(const char *path
, struct fuse_file_info
*)) dlsym(dlopen_handle
, "cg_releasedir");
470 lxcfs_error("%s\n", error
);
474 return cg_releasedir(path
, fi
);
479 * these just delegate to the /proc and /cgroup ops as
483 static int lxcfs_getattr(const char *path
, struct stat
*sb
)
488 if (strcmp(path
, "/") == 0) {
489 if (clock_gettime(CLOCK_REALTIME
, &now
) < 0)
491 sb
->st_uid
= sb
->st_gid
= 0;
492 sb
->st_atim
= sb
->st_mtim
= sb
->st_ctim
= now
;
494 sb
->st_mode
= S_IFDIR
| 00755;
499 if (strncmp(path
, "/cgroup", 7) == 0) {
501 ret
= do_cg_getattr(path
, sb
);
505 if (strncmp(path
, "/proc", 5) == 0) {
507 ret
= do_proc_getattr(path
, sb
);
514 static int lxcfs_opendir(const char *path
, struct fuse_file_info
*fi
)
517 if (strcmp(path
, "/") == 0)
520 if (strncmp(path
, "/cgroup", 7) == 0) {
522 ret
= do_cg_opendir(path
, fi
);
526 if (strcmp(path
, "/proc") == 0)
531 static int lxcfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
, off_t offset
,
532 struct fuse_file_info
*fi
)
535 if (strcmp(path
, "/") == 0) {
536 if (filler(buf
, ".", NULL
, 0) != 0 ||
537 filler(buf
, "..", NULL
, 0) != 0 ||
538 filler(buf
, "proc", NULL
, 0) != 0 ||
539 filler(buf
, "cgroup", NULL
, 0) != 0)
543 if (strncmp(path
, "/cgroup", 7) == 0) {
545 ret
= do_cg_readdir(path
, buf
, filler
, offset
, fi
);
549 if (strcmp(path
, "/proc") == 0) {
551 ret
= do_proc_readdir(path
, buf
, filler
, offset
, fi
);
558 static int lxcfs_access(const char *path
, int mode
)
562 if (strcmp(path
, "/") == 0 && (mode
& W_OK
) == 0)
565 if (strncmp(path
, "/cgroup", 7) == 0) {
567 ret
= do_cg_access(path
, mode
);
571 if (strncmp(path
, "/proc", 5) == 0) {
573 ret
= do_proc_access(path
, mode
);
581 static int lxcfs_releasedir(const char *path
, struct fuse_file_info
*fi
)
584 if (strcmp(path
, "/") == 0)
586 if (strncmp(path
, "/cgroup", 7) == 0) {
588 ret
= do_cg_releasedir(path
, fi
);
592 if (strcmp(path
, "/proc") == 0)
597 static int lxcfs_open(const char *path
, struct fuse_file_info
*fi
)
600 if (strncmp(path
, "/cgroup", 7) == 0) {
602 ret
= do_cg_open(path
, fi
);
606 if (strncmp(path
, "/proc", 5) == 0) {
608 ret
= do_proc_open(path
, fi
);
616 static int lxcfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
617 struct fuse_file_info
*fi
)
620 if (strncmp(path
, "/cgroup", 7) == 0) {
622 ret
= do_cg_read(path
, buf
, size
, offset
, fi
);
626 if (strncmp(path
, "/proc", 5) == 0) {
628 ret
= do_proc_read(path
, buf
, size
, offset
, fi
);
636 int lxcfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
637 struct fuse_file_info
*fi
)
640 if (strncmp(path
, "/cgroup", 7) == 0) {
642 ret
= do_cg_write(path
, buf
, size
, offset
, fi
);
650 static int lxcfs_flush(const char *path
, struct fuse_file_info
*fi
)
655 static int lxcfs_release(const char *path
, struct fuse_file_info
*fi
)
658 if (strncmp(path
, "/cgroup", 7) == 0) {
660 ret
= do_cg_release(path
, fi
);
664 if (strncmp(path
, "/proc", 5) == 0) {
666 ret
= do_proc_release(path
, fi
);
674 static int lxcfs_fsync(const char *path
, int datasync
, struct fuse_file_info
*fi
)
679 int lxcfs_mkdir(const char *path
, mode_t mode
)
682 if (strncmp(path
, "/cgroup", 7) == 0) {
684 ret
= do_cg_mkdir(path
, mode
);
692 int lxcfs_chown(const char *path
, uid_t uid
, gid_t gid
)
695 if (strncmp(path
, "/cgroup", 7) == 0) {
697 ret
= do_cg_chown(path
, uid
, gid
);
702 if (strncmp(path
, "/proc", 5) == 0)
709 * cat first does a truncate before doing ops->write. This doesn't
710 * really make sense for cgroups. So just return 0 always but do
713 int lxcfs_truncate(const char *path
, off_t newsize
)
715 if (strncmp(path
, "/cgroup", 7) == 0)
720 int lxcfs_rmdir(const char *path
)
723 if (strncmp(path
, "/cgroup", 7) == 0) {
725 ret
= do_cg_rmdir(path
);
732 int lxcfs_chmod(const char *path
, mode_t mode
)
735 if (strncmp(path
, "/cgroup", 7) == 0) {
737 ret
= do_cg_chmod(path
, mode
);
742 if (strncmp(path
, "/proc", 5) == 0)
748 const struct fuse_operations lxcfs_ops
= {
749 .getattr
= lxcfs_getattr
,
753 .mkdir
= lxcfs_mkdir
,
755 .rmdir
= lxcfs_rmdir
,
759 .chmod
= lxcfs_chmod
,
760 .chown
= lxcfs_chown
,
761 .truncate
= lxcfs_truncate
,
766 .release
= lxcfs_release
,
767 .write
= lxcfs_write
,
770 .flush
= lxcfs_flush
,
771 .fsync
= lxcfs_fsync
,
778 .opendir
= lxcfs_opendir
,
779 .readdir
= lxcfs_readdir
,
780 .releasedir
= lxcfs_releasedir
,
785 .access
= lxcfs_access
,
793 fprintf(stderr
, "Usage:\n");
794 fprintf(stderr
, "\n");
795 fprintf(stderr
, "lxcfs [-f|-d] -l [-p pidfile] mountpoint\n");
796 fprintf(stderr
, " -f running foreground by default; -d enable debug output \n");
797 fprintf(stderr
, " -l use loadavg \n");
798 fprintf(stderr
, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH
);
799 fprintf(stderr
, "lxcfs -h\n");
803 static bool is_help(char *w
)
805 if (strcmp(w
, "-h") == 0 ||
806 strcmp(w
, "--help") == 0 ||
807 strcmp(w
, "-help") == 0 ||
808 strcmp(w
, "help") == 0)
813 bool swallow_arg(int *argcp
, char *argv
[], char *which
)
817 for (i
= 1; argv
[i
]; i
++) {
818 if (strcmp(argv
[i
], which
) != 0)
820 for (; argv
[i
]; i
++) {
829 bool swallow_option(int *argcp
, char *argv
[], char *opt
, char **v
)
833 for (i
= 1; argv
[i
]; i
++) {
836 if (strcmp(argv
[i
], opt
) != 0)
839 *v
= strdup(argv
[i
+1]);
841 for (; argv
[i
+1]; i
++) {
850 static int set_pidfile(char *pidfile
)
857 fl
.l_whence
= SEEK_SET
;
861 fd
= open(pidfile
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
863 fprintf(stderr
, "Could not open pidfile %s: %m\n", pidfile
);
867 if (fcntl(fd
, F_SETLK
, &fl
) == -1) {
868 if (errno
== EAGAIN
|| errno
== EACCES
) {
869 fprintf(stderr
, "PID file '%s' is already locked.\n", pidfile
);
873 fprintf(stderr
, "Warning; unable to lock PID file, proceeding.\n");
876 if (ftruncate(fd
, 0) == -1) {
877 fprintf(stderr
, "Error truncating PID file '%s': %m", pidfile
);
882 snprintf(buf
, 50, "%ld\n", (long) getpid());
883 if (write(fd
, buf
, strlen(buf
)) != strlen(buf
)) {
884 fprintf(stderr
, "Error writing to PID file '%s': %m", pidfile
);
892 int main(int argc
, char *argv
[])
894 int ret
= EXIT_FAILURE
;
896 char *pidfile
= NULL
, *saveptr
= NULL
, *token
= NULL
, *v
= NULL
;
898 bool debug
= false, nonempty
= false;
899 bool load_use
= false;
901 * what we pass to fuse_main is:
902 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
904 int nargs
= 5, cnt
= 0;
907 /* accomodate older init scripts */
908 swallow_arg(&argc
, argv
, "-s");
909 swallow_arg(&argc
, argv
, "-f");
910 debug
= swallow_arg(&argc
, argv
, "-d");
911 if (swallow_arg(&argc
, argv
, "-l")) {
914 if (swallow_option(&argc
, argv
, "-o", &v
)) {
915 /* Parse multiple values */
916 for (; (token
= strtok_r(v
, ",", &saveptr
)); v
= NULL
) {
917 if (strcmp(token
, "allow_other") == 0) {
918 /* Noop. this is the default. Always enabled. */
919 } else if (strcmp(token
, "nonempty") == 0) {
923 fprintf(stderr
, "Warning: unexpected fuse option %s\n", v
);
930 if (swallow_option(&argc
, argv
, "-p", &v
))
933 if (argc
== 2 && strcmp(argv
[1], "--version") == 0) {
934 fprintf(stderr
, "%s\n", VERSION
);
937 if (argc
!= 2 || is_help(argv
[1]))
941 if (signal(SIGUSR1
, reload_handler
) == SIG_ERR
) {
942 fprintf(stderr
, "Error setting USR1 signal handler: %m\n");
946 newargv
[cnt
++] = argv
[0];
948 newargv
[cnt
++] = "-d";
950 newargv
[cnt
++] = "-f";
951 newargv
[cnt
++] = "-o";
953 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
955 newargv
[cnt
++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
956 newargv
[cnt
++] = argv
[1];
957 newargv
[cnt
++] = NULL
;
960 pidfile_len
= strlen(RUNTIME_PATH
) + strlen("/lxcfs.pid") + 1;
961 pidfile
= alloca(pidfile_len
);
962 snprintf(pidfile
, pidfile_len
, "%s/lxcfs.pid", RUNTIME_PATH
);
964 if ((pidfd
= set_pidfile(pidfile
)) < 0)
967 if (load_use
&& start_loadavg() != 0)
970 if (!fuse_main(nargs
, newargv
, &lxcfs_ops
, NULL
))
977 dlclose(dlopen_handle
);