X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=lxcfs.c;h=fe381480ca3059097becf15415006cb4894f51fa;hb=9c480eb7bc9e395fe150ba636837a94f0b75f723;hp=b36986cd97deba4f691a29132dd5af9f1ac91e2e;hpb=59120f046788b810c00f4de65fcbe634ff2250a8;p=mirror_lxcfs.git diff --git a/lxcfs.c b/lxcfs.c index b36986c..fe38148 100644 --- a/lxcfs.c +++ b/lxcfs.c @@ -8,28 +8,30 @@ #define FUSE_USE_VERSION 26 -#include +#include #include +#include +#include #include #include -#include -#include -#include -#include -#include -#include #include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include #include -#include +#include +#include +#include -#include "config.h" // for VERSION #include "bindings.h" +#include "config.h" // for VERSION void *dlopen_handle; @@ -42,7 +44,7 @@ static void lock_mutex(pthread_mutex_t *l) int ret; if ((ret = pthread_mutex_lock(l)) != 0) { - fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret)); + lxcfs_error("returned:%d %s\n", ret, strerror(ret)); exit(1); } } @@ -52,7 +54,7 @@ static void unlock_mutex(pthread_mutex_t *l) int ret; if ((ret = pthread_mutex_unlock(l)) != 0) { - fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret)); + lxcfs_error("returned:%d %s\n", ret, strerror(ret)); exit(1); } } @@ -67,30 +69,40 @@ static void users_unlock(void) unlock_mutex(&user_count_mutex); } -static int need_reload; +static volatile sig_atomic_t need_reload; /* do_reload - reload the dynamic library. Done under * lock and when we know the user_count was 0 */ static void do_reload(void) { - if (dlopen_handle) + char lxcfs_lib_path[PATH_MAX]; + if (dlopen_handle) { + lxcfs_debug("%s\n", "Closing liblxcfs.so handle."); dlclose(dlopen_handle); + } /* First try loading using ld.so */ dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY); - if (dlopen_handle) + if (dlopen_handle) { + lxcfs_debug("%s\n", "Successfully called dlopen() on liblxcfs.so."); goto good; + } - /* Fall back to loading from /usr/lib/lxcfs/liblxcfs.so */ - dlopen_handle = dlopen(LIBDIR "lxcfs/liblxcfs.so", RTLD_LAZY); +#ifdef LIBDIR + /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */ + snprintf(lxcfs_lib_path, PATH_MAX, "%s/lxcfs/liblxcfs.so", LIBDIR); +#else + snprintf(lxcfs_lib_path, PATH_MAX, "/usr/local/lib/lxcfs/liblxcfs.so"); +#endif + dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY); if (!dlopen_handle) { - fprintf(stderr, "Failed to open liblxcfs\n"); + lxcfs_error("Failed to open liblxcfs.so: %s.\n", dlerror()); _exit(1); } good: if (need_reload) - fprintf(stderr, "lxcfs: reloaded\n"); + lxcfs_error("%s\n", "lxcfs: reloaded"); need_reload = 0; } @@ -112,10 +124,7 @@ static void down_users(void) static void reload_handler(int sig) { - fprintf(stderr, "lxcfs: caught a SIGUSR1. Reloading\n"); - users_lock(); need_reload = 1; - users_unlock(); } /* Functions to run the library methods */ @@ -127,7 +136,7 @@ static int do_cg_getattr(const char *path, struct stat *sb) cg_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "cg_getattr"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_getattr: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -142,7 +151,7 @@ static int do_proc_getattr(const char *path, struct stat *sb) proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "proc_getattr: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -160,7 +169,7 @@ static int do_cg_read(const char *path, char *buf, size_t size, off_t offset, cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_read"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_read: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -178,7 +187,7 @@ static int do_proc_read(const char *path, char *buf, size_t size, off_t offset, proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "proc_read: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -195,7 +204,7 @@ static int do_cg_write(const char *path, const char *buf, size_t size, off_t off cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_write"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_write: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -210,7 +219,7 @@ static int do_cg_mkdir(const char *path, mode_t mode) cg_mkdir = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_mkdir"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_mkdir: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -225,7 +234,7 @@ static int do_cg_chown(const char *path, uid_t uid, gid_t gid) cg_chown = (int (*)(const char *, uid_t, gid_t)) dlsym(dlopen_handle, "cg_chown"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_chown: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -240,7 +249,7 @@ static int do_cg_rmdir(const char *path) cg_rmdir = (int (*)(const char *path)) dlsym(dlopen_handle, "cg_rmdir"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_rmdir: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -255,7 +264,7 @@ static int do_cg_chmod(const char *path, mode_t mode) cg_chmod = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_chmod"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_chmod: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -273,7 +282,7 @@ static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_readdir"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_readdir: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -291,7 +300,7 @@ static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_readdir"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "proc_readdir: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -306,13 +315,28 @@ static int do_cg_open(const char *path, struct fuse_file_info *fi) cg_open = (int (*)(const char *, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_open"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_open: %s\n", error); + lxcfs_error("%s\n", error); return -1; } return cg_open(path, fi); } +static int do_cg_access(const char *path, int mode) +{ + int (*cg_access)(const char *path, int mode); + char *error; + dlerror(); /* Clear any existing error */ + cg_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "cg_access"); + error = dlerror(); + if (error != NULL) { + lxcfs_error("%s\n", error); + return -1; + } + + return cg_access(path, mode); +} + static int do_proc_open(const char *path, struct fuse_file_info *fi) { int (*proc_open)(const char *path, struct fuse_file_info *fi); @@ -321,13 +345,28 @@ static int do_proc_open(const char *path, struct fuse_file_info *fi) proc_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "proc_open"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "proc_open: %s\n", error); + lxcfs_error("%s\n", error); return -1; } return proc_open(path, fi); } +static int do_proc_access(const char *path, int mode) +{ + int (*proc_access)(const char *path, int mode); + char *error; + dlerror(); /* Clear any existing error */ + proc_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "proc_access"); + error = dlerror(); + if (error != NULL) { + lxcfs_error("%s\n", error); + return -1; + } + + return proc_access(path, mode); +} + static int do_cg_release(const char *path, struct fuse_file_info *fi) { int (*cg_release)(const char *path, struct fuse_file_info *fi); @@ -336,7 +375,7 @@ static int do_cg_release(const char *path, struct fuse_file_info *fi) cg_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_release"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_release: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -351,7 +390,7 @@ static int do_proc_release(const char *path, struct fuse_file_info *fi) proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "proc_release: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -366,7 +405,7 @@ static int do_cg_opendir(const char *path, struct fuse_file_info *fi) cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "cg_opendir"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_opendir: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -381,7 +420,7 @@ static int do_cg_releasedir(const char *path, struct fuse_file_info *fi) cg_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_releasedir"); error = dlerror(); if (error != NULL) { - fprintf(stderr, "cg_releasedir: %s\n", error); + lxcfs_error("%s\n", error); return -1; } @@ -397,11 +436,19 @@ static int do_cg_releasedir(const char *path, struct fuse_file_info *fi) static int lxcfs_getattr(const char *path, struct stat *sb) { int ret; + struct timespec now; + if (strcmp(path, "/") == 0) { + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return -EINVAL; + sb->st_uid = sb->st_gid = 0; + sb->st_atim = sb->st_mtim = sb->st_ctim = now; + sb->st_size = 0; sb->st_mode = S_IFDIR | 00755; sb->st_nlink = 2; return 0; } + if (strncmp(path, "/cgroup", 7) == 0) { up_users(); ret = do_cg_getattr(path, sb); @@ -414,7 +461,7 @@ static int lxcfs_getattr(const char *path, struct stat *sb) down_users(); return ret; } - return -EINVAL; + return -ENOENT; } static int lxcfs_opendir(const char *path, struct fuse_file_info *fi) @@ -439,9 +486,11 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of { int ret; if (strcmp(path, "/") == 0) { - if (filler(buf, "proc", NULL, 0) != 0 || - filler(buf, "cgroup", NULL, 0) != 0) - return -EINVAL; + if (filler(buf, ".", NULL, 0) != 0 || + filler(buf, "..", NULL, 0) != 0 || + filler(buf, "proc", NULL, 0) != 0 || + filler(buf, "cgroup", NULL, 0) != 0) + return -ENOMEM; return 0; } if (strncmp(path, "/cgroup", 7) == 0) { @@ -456,7 +505,30 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of down_users(); return ret; } - return -EINVAL; + return -ENOENT; +} + +static int lxcfs_access(const char *path, int mode) +{ + int ret; + + if (strcmp(path, "/") == 0 && (mode & W_OK) == 0) + return 0; + + if (strncmp(path, "/cgroup", 7) == 0) { + up_users(); + ret = do_cg_access(path, mode); + down_users(); + return ret; + } + if (strncmp(path, "/proc", 5) == 0) { + up_users(); + ret = do_proc_access(path, mode); + down_users(); + return ret; + } + + return -EACCES; } static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi) @@ -491,7 +563,7 @@ static int lxcfs_open(const char *path, struct fuse_file_info *fi) return ret; } - return -EINVAL; + return -EACCES; } static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset, @@ -567,7 +639,7 @@ int lxcfs_mkdir(const char *path, mode_t mode) return ret; } - return -EINVAL; + return -EPERM; } int lxcfs_chown(const char *path, uid_t uid, gid_t gid) @@ -580,7 +652,10 @@ int lxcfs_chown(const char *path, uid_t uid, gid_t gid) return ret; } - return -EINVAL; + if (strncmp(path, "/proc", 5) == 0) + return -EPERM; + + return -ENOENT; } /* @@ -592,7 +667,7 @@ int lxcfs_truncate(const char *path, off_t newsize) { if (strncmp(path, "/cgroup", 7) == 0) return 0; - return -EINVAL; + return -EPERM; } int lxcfs_rmdir(const char *path) @@ -604,7 +679,7 @@ int lxcfs_rmdir(const char *path) down_users(); return ret; } - return -EINVAL; + return -EPERM; } int lxcfs_chmod(const char *path, mode_t mode) @@ -616,7 +691,11 @@ int lxcfs_chmod(const char *path, mode_t mode) down_users(); return ret; } - return -EINVAL; + + if (strncmp(path, "/proc", 5) == 0) + return -EPERM; + + return -ENOENT; } const struct fuse_operations lxcfs_ops = { @@ -656,19 +735,21 @@ const struct fuse_operations lxcfs_ops = { .fsyncdir = NULL, .init = NULL, .destroy = NULL, - .access = NULL, + .access = lxcfs_access, .create = NULL, .ftruncate = NULL, .fgetattr = NULL, }; -static void usage(const char *me) +static void usage() { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\n"); - fprintf(stderr, "%s [-p pidfile] mountpoint\n", me); + fprintf(stderr, "lxcfs [-f|-d] -l [-p pidfile] mountpoint\n"); + fprintf(stderr, " -f running foreground by default; -d enable debug output \n"); + fprintf(stderr, " -l use loadavg \n"); fprintf(stderr, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH); - fprintf(stderr, "%s -h\n", me); + fprintf(stderr, "lxcfs -h\n"); exit(1); } @@ -682,7 +763,7 @@ static bool is_help(char *w) return false; } -void swallow_arg(int *argcp, char *argv[], char *which) +bool swallow_arg(int *argcp, char *argv[], char *which) { int i; @@ -693,8 +774,9 @@ void swallow_arg(int *argcp, char *argv[], char *which) argv[i] = argv[i+1]; } (*argcp)--; - return; + return true; } + return false; } bool swallow_option(int *argcp, char *argv[], char *opt, char **v) @@ -718,127 +800,6 @@ bool swallow_option(int *argcp, char *argv[], char *opt, char **v) return false; } -static bool mkdir_p(const char *dir, mode_t mode) -{ - const char *tmp = dir; - const char *orig = dir; - char *makeme; - - do { - dir = tmp + strspn(tmp, "/"); - tmp = dir + strcspn(dir, "/"); - makeme = strndup(orig, dir - orig); - if (!makeme) - return false; - if (mkdir(makeme, mode) && errno != EEXIST) { - fprintf(stderr, "failed to create directory '%s': %s", - makeme, strerror(errno)); - free(makeme); - return false; - } - free(makeme); - } while(tmp != dir); - - return true; -} - -static bool umount_if_mounted(void) -{ - if (umount2(basedir, MNT_DETACH) < 0 && errno != EINVAL) { - fprintf(stderr, "failed to umount %s: %s\n", basedir, - strerror(errno)); - return false; - } - return true; -} - -static bool setup_cgfs_dir(void) -{ - if (!mkdir_p(basedir, 0700)) { - fprintf(stderr, "Failed to create lxcfs cgdir\n"); - return false; - } - if (!umount_if_mounted()) { - fprintf(stderr, "Failed to clean up old lxcfs cgdir\n"); - return false; - } - if (mount("tmpfs", basedir, "tmpfs", 0, "size=100000,mode=700") < 0) { - fprintf(stderr, "Failed to mount tmpfs for private controllers\n"); - return false; - } - return true; -} - -static bool do_mount_cgroup(char *controller) -{ - char *target; - size_t len; - int ret; - - len = strlen(basedir) + strlen(controller) + 2; - target = alloca(len); - ret = snprintf(target, len, "%s/%s", basedir, controller); - if (ret < 0 || ret >= len) - return false; - if (mkdir(target, 0755) < 0 && errno != EEXIST) - return false; - if (mount(controller, target, "cgroup", 0, controller) < 0) { - fprintf(stderr, "Failed mounting cgroup %s\n", controller); - return false; - } - return true; -} - -static bool do_mount_cgroups(void) -{ - bool ret; - FILE *f; - char *line = NULL; - size_t len = 0; - - if ((f = fopen("/proc/self/cgroup", "r")) == NULL) { - fprintf(stderr, "Error opening /proc/self/cgroup: %s\n", strerror(errno)); - return false; - } - - while (getline(&line, &len, f) != -1) { - char *p, *p2; - - p = strchr(line, ':'); - if (!p) - goto out; - *(p++) = '\0'; - - p2 = strrchr(p, ':'); - if (!p2) - goto out; - *p2 = '\0'; - - if (!do_mount_cgroup(p)) - goto out; - } - ret = true; - -out: - free(line); - fclose(f); - return ret; -} - -static bool cgfs_setup_controllers(void) -{ - if (!setup_cgfs_dir()) { - return false; - } - - if (!do_mount_cgroups()) { - fprintf(stderr, "Failed to set up cgroup mounts\n"); - return false; - } - - return true; -} - static int set_pidfile(char *pidfile) { int fd; @@ -852,7 +813,7 @@ static int set_pidfile(char *pidfile) fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { - fprintf(stderr, "Could not open pidfile %s: %m", pidfile); + fprintf(stderr, "Could not open pidfile %s: %m\n", pidfile); return -1; } @@ -883,12 +844,20 @@ static int set_pidfile(char *pidfile) int main(int argc, char *argv[]) { - int ret = -1, pidfd; - char *pidfile = NULL, *v = NULL; + int ret = EXIT_FAILURE; + int pidfd = -1; + char *pidfile = NULL, *saveptr = NULL, *token = NULL, *v = NULL; size_t pidfile_len; + bool debug = false, nonempty = false; + pthread_t pid; + int s = 0; + char *error; + bool load_use = false; + pthread_t (*load_daemon)(int); + void (*load_free)(void); /* * what we pass to fuse_main is: - * argv[0] -s -f -o allow_other,directio argv[1] NULL + * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL */ int nargs = 5, cnt = 0; char *newargv[6]; @@ -896,10 +865,22 @@ int main(int argc, char *argv[]) /* accomodate older init scripts */ swallow_arg(&argc, argv, "-s"); swallow_arg(&argc, argv, "-f"); + debug = swallow_arg(&argc, argv, "-d"); + if (swallow_arg(&argc, argv, "-l")) { + load_use = true; + } if (swallow_option(&argc, argv, "-o", &v)) { - if (strcmp(v, "allow_other") != 0) { - fprintf(stderr, "Warning: unexpected fuse option %s\n", v); - exit(1); + /* Parse multiple values */ + for (; (token = strtok_r(v, ",", &saveptr)); v = NULL) { + if (strcmp(token, "allow_other") == 0) { + /* Noop. this is the default. Always enabled. */ + } else if (strcmp(token, "nonempty") == 0) { + nonempty = true; + } else { + free(v); + fprintf(stderr, "Warning: unexpected fuse option %s\n", v); + exit(EXIT_FAILURE); + } } free(v); v = NULL; @@ -909,24 +890,30 @@ int main(int argc, char *argv[]) if (argc == 2 && strcmp(argv[1], "--version") == 0) { fprintf(stderr, "%s\n", VERSION); - exit(0); + exit(EXIT_SUCCESS); } if (argc != 2 || is_help(argv[1])) - usage(argv[0]); + usage(); do_reload(); - signal(SIGUSR1, reload_handler); + if (signal(SIGUSR1, reload_handler) == SIG_ERR) { + fprintf(stderr, "Error setting USR1 signal handler: %m\n"); + goto out; + } newargv[cnt++] = argv[0]; - newargv[cnt++] = "-f"; + if (debug) + newargv[cnt++] = "-d"; + else + newargv[cnt++] = "-f"; newargv[cnt++] = "-o"; - newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5"; + if (nonempty) + newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty"; + else + newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5"; newargv[cnt++] = argv[1]; newargv[cnt++] = NULL; - if (!cgfs_setup_controllers()) - goto out; - if (!pidfile) { pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1; pidfile = alloca(pidfile_len); @@ -935,12 +922,49 @@ int main(int argc, char *argv[]) if ((pidfd = set_pidfile(pidfile)) < 0) goto out; - ret = fuse_main(nargs, newargv, &lxcfs_ops, NULL); + if (load_use == true) { + dlerror(); /* Clear any existing error */ - dlclose(dlopen_handle); - unlink(pidfile); - close(pidfd); + load_daemon = (pthread_t (*)(int)) dlsym(dlopen_handle, "load_daemon"); + error = dlerror(); + if (error != NULL) { + lxcfs_error("load_daemon fails:%s\n", error); + goto out; + } + pid = load_daemon(1); + if (pid == 0) + goto out; + } + if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL)) + ret = EXIT_SUCCESS; + if (load_use == true) { + s = pthread_cancel(pid); + if (s == 0) { + s = pthread_join(pid, NULL); /* Make sure sub thread has been canceled. */ + if (s != 0) { + lxcfs_error("%s\n", "load_free error!"); + goto out; + } + dlerror(); /* Clear any existing error */ + + load_free = (void (*)(void)) dlsym(dlopen_handle, "load_free"); + error = dlerror(); + if (error != NULL) { + lxcfs_error("load_free error: %s\n", error); + goto out; + } + load_free(); + } else { + lxcfs_error("%s\n", "load_free error!"); + } + } out: - return ret; + if (dlopen_handle) + dlclose(dlopen_handle); + if (pidfile) + unlink(pidfile); + if (pidfd > 0) + close(pidfd); + exit(ret); }