]> git.proxmox.com Git - mirror_lxcfs.git/blobdiff - lxcfs.c
lxcfs: add --disable-cfs
[mirror_lxcfs.git] / lxcfs.c
diff --git a/lxcfs.c b/lxcfs.c
index fe1dddd3f6a8f6eb5fd0db98af90727f30a24e64..1f4d902861db5740b59db045b882eff3aa81ec24 100644 (file)
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -6,30 +6,42 @@
  * See COPYING file for details.
  */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef FUSE_USE_VERSION
 #define FUSE_USE_VERSION 26
+#endif
 
-#include <stdio.h>
+#define _FILE_OFFSET_BITS 64
+
+#include <alloca.h>
 #include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <fuse.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <time.h>
-#include <string.h>
-#include <stdlib.h>
 #include <libgen.h>
-#include <sched.h>
 #include <pthread.h>
-#include <dlfcn.h>
+#include <sched.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <wait.h>
 #include <linux/sched.h>
-#include <sys/socket.h>
-#include <sys/mount.h>
 #include <sys/epoll.h>
-#include <wait.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <linux/limits.h>
 
-#include "config.h" // for VERSION
 #include "bindings.h"
+#include "config.h"
+#include "macro.h"
+#include "memory_utils.h"
 
 void *dlopen_handle;
 
@@ -41,55 +53,113 @@ 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));
-               exit(1);
-       }
+       ret = pthread_mutex_lock(l);
+       if (ret)
+               log_exit("%s - returned: %d\n", strerror(ret), ret);
 }
 
 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));
-               exit(1);
-       }
+       ret = pthread_mutex_unlock(l);
+       if (ret)
+               log_exit("%s - returned: %d\n", strerror(ret), ret);
 }
 
-static void users_lock(void)
+static inline void users_lock(void)
 {
        lock_mutex(&user_count_mutex);
 }
 
-static void users_unlock(void)
+static inline void users_unlock(void)
 {
        unlock_mutex(&user_count_mutex);
 }
 
+static pthread_t loadavg_pid = 0;
+
+/* Returns zero on success */
+static int start_loadavg(void)
+{
+       char *error;
+       pthread_t (*__load_daemon)(int);
+
+       dlerror();
+       __load_daemon = (pthread_t(*)(int))dlsym(dlopen_handle, "load_daemon");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to start loadavg daemon", error);
+
+       loadavg_pid = __load_daemon(1);
+       if (!loadavg_pid)
+               return -1;
+
+       return 0;
+}
+
+/* Returns zero on success */
+static int stop_loadavg(void)
+{
+       char *error;
+       int (*__stop_load_daemon)(pthread_t);
+
+       __stop_load_daemon = (int (*)(pthread_t))dlsym(dlopen_handle, "stop_load_daemon");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to stop loadavg daemon", error);
+
+       if (__stop_load_daemon(loadavg_pid))
+               return -1;
+
+       return 0;
+}
+
 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)
+       int ret;
+       char lxcfs_lib_path[PATH_MAX];
+
+       if (loadavg_pid > 0)
+               stop_loadavg();
+
+       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;
-
-       dlopen_handle = dlopen("/usr/lib/lxcfs/liblxcfs.so", RTLD_LAZY);
-       if (!dlopen_handle) {
-               fprintf(stderr, "Failed to open liblxcfs\n");
-               _exit(1);
        }
 
+#ifdef LIBDIR
+       /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
+        ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "%s/lxcfs/liblxcfs.so", LIBDIR);
+#else
+        ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "/usr/local/lib/lxcfs/liblxcfs.so");
+#endif
+       if (ret < 0 || ret >= sizeof(lxcfs_lib_path))
+               log_exit("Failed to create path to open liblxcfs");
+
+        dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY);
+       if (!dlopen_handle)
+               log_exit("%s - Failed to open liblxcfs.so", dlerror());
+       else
+               lxcfs_debug("Successfully called dlopen() on %s", lxcfs_lib_path);
+
 good:
+       if (loadavg_pid > 0)
+               start_loadavg();
+
        if (need_reload)
-               fprintf(stderr, "lxcfs: reloaded\n");
+               lxcfs_error("%s\n", "lxcfs: reloaded");
        need_reload = 0;
 }
 
@@ -117,305 +187,427 @@ static void reload_handler(int sig)
 /* Functions to run the library methods */
 static int do_cg_getattr(const char *path, struct stat *sb)
 {
-       int (*cg_getattr)(const char *path, struct stat *sb);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "cg_getattr");
+       int (*__cg_getattr)(const char *path, struct stat *sb);
+
+       dlerror();
+       __cg_getattr = (int (*)(const char *, struct stat *))dlsym(dlopen_handle, "cg_getattr");
        error = dlerror();
-       if (error != NULL) {
-               fprintf(stderr, "cg_getattr: %s\n", error);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_getattr()", error);
 
-       return cg_getattr(path, sb);
+       return __cg_getattr(path, sb);
 }
 
 static int do_proc_getattr(const char *path, struct stat *sb)
 {
-       int (*proc_getattr)(const char *path, struct stat *sb);
        char *error;
-       dlerror();    /* Clear any existing error */
-       proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
+       int (*__proc_getattr)(const char *path, struct stat *sb);
+
+       dlerror();
+       __proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
        error = dlerror();
-       if (error != NULL) {
-               fprintf(stderr, "proc_getattr: %s\n", error);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find proc_getattr()", error);
+
+       return __proc_getattr(path, sb);
+}
+
+static int do_sys_getattr(const char *path, struct stat *sb)
+{
+       char *error;
+       int (*__sys_getattr)(const char *path, struct stat *sb);
 
-       return proc_getattr(path, sb);
+       dlerror();
+       __sys_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "sys_getattr");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_getattr()", error);
+
+       return __sys_getattr(path, sb);
 }
 
 static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
-               struct fuse_file_info *fi)
+                     struct fuse_file_info *fi)
 {
-       int (*cg_read)(const char *path, char *buf, size_t size, off_t offset,
-               struct fuse_file_info *fi);
        char *error;
+       int (*__cg_read)(const char *path, char *buf, size_t size, off_t offset,
+                        struct fuse_file_info *fi);
 
-       dlerror();    /* Clear any existing error */
-       cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_read");
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_read()", error);
 
-       return cg_read(path, buf, size, offset, fi);
+       return __cg_read(path, buf, size, offset, fi);
 }
 
 static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
-               struct fuse_file_info *fi)
+                       struct fuse_file_info *fi)
 {
-       int (*proc_read)(const char *path, char *buf, size_t size, off_t offset,
-               struct fuse_file_info *fi);
        char *error;
+       int (*__proc_read)(const char *path, char *buf, size_t size,
+                          off_t offset, struct fuse_file_info *fi);
 
-       dlerror();    /* Clear any existing error */
-       proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read");
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find proc_read()", error);
 
-       return proc_read(path, buf, size, offset, fi);
+       return __proc_read(path, buf, size, offset, fi);
 }
 
-static int do_cg_write(const char *path, const char *buf, size_t size, off_t offset,
-            struct fuse_file_info *fi)
+static int do_sys_read(const char *path, char *buf, size_t size, off_t offset,
+                      struct fuse_file_info *fi)
 {
-       int (*cg_write)(const char *path, const char *buf, size_t size, off_t offset,
-            struct fuse_file_info *fi);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_write");
+       int (*__sys_read)(const char *path, char *buf, size_t size,
+                         off_t offset, struct fuse_file_info *fi);
+
+       dlerror();
+       __sys_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_read");
        error = dlerror();
-       if (error != NULL) {
-               fprintf(stderr, "cg_write: %s\n", error);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_read()", error);
 
-       return cg_write(path, buf, size, offset, fi);
+       return __sys_read(path, buf, size, offset, fi);
+}
+
+static int do_cg_write(const char *path, const char *buf, size_t size,
+                      off_t offset, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__cg_write)(const char *path, const char *buf, size_t size,
+                         off_t offset, struct fuse_file_info *fi);
+
+       dlerror();
+       __cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_write");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_write()", error);
+
+       return __cg_write(path, buf, size, offset, fi);
 }
 
 static int do_cg_mkdir(const char *path, mode_t mode)
 {
-       int (*cg_mkdir)(const char *path, mode_t mode);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_mkdir = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_mkdir");
+       int (*__cg_mkdir)(const char *path, mode_t mode);
+
+       dlerror();
+       __cg_mkdir = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_mkdir");
        error = dlerror();
-       if (error != NULL) {
-               fprintf(stderr, "cg_mkdir: %s\n", error);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_mkdir()", error);
 
-       return cg_mkdir(path, mode);
+       return __cg_mkdir(path, mode);
 }
 
 static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
 {
-       int (*cg_chown)(const char *path, uid_t uid, gid_t gid);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_chown = (int (*)(const char *, uid_t, gid_t)) dlsym(dlopen_handle, "cg_chown");
+       int (*__cg_chown)(const char *path, uid_t uid, gid_t gid);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_chown()", error);
 
-       return cg_chown(path, uid, gid);
+       return __cg_chown(path, uid, gid);
 }
 
 static int do_cg_rmdir(const char *path)
 {
-       int (*cg_rmdir)(const char *path);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_rmdir = (int (*)(const char *path)) dlsym(dlopen_handle, "cg_rmdir");
+       int (*__cg_rmdir)(const char *path);
+
+       dlerror();
+       __cg_rmdir = (int (*)(const char *path))dlsym(dlopen_handle, "cg_rmdir");
        error = dlerror();
-       if (error != NULL) {
-               fprintf(stderr, "cg_rmdir: %s\n", error);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_rmdir()", error);
 
-       return cg_rmdir(path);
+       return __cg_rmdir(path);
 }
 
 static int do_cg_chmod(const char *path, mode_t mode)
 {
-       int (*cg_chmod)(const char *path, mode_t mode);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_chmod = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_chmod");
+       int (*__cg_chmod)(const char *path, mode_t mode);
+
+       dlerror();
+       __cg_chmod = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_chmod");
        error = dlerror();
-       if (error != NULL) {
-               fprintf(stderr, "cg_chmod: %s\n", error);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_chmod()", error);
 
-       return cg_chmod(path, mode);
+       return __cg_chmod(path, mode);
 }
 
-static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
-               struct fuse_file_info *fi)
+static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                        off_t offset, struct fuse_file_info *fi)
 {
-       int (*cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
-               struct fuse_file_info *fi);
        char *error;
+       int (*__cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
+                           off_t offset, struct fuse_file_info *fi);
 
-       dlerror();    /* Clear any existing error */
-       cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_readdir");
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_readdir()", error);
 
-       return cg_readdir(path, buf, filler, offset, fi);
+       return __cg_readdir(path, buf, filler, offset, fi);
 }
 
-static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
-               struct fuse_file_info *fi)
+static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                          off_t offset, struct fuse_file_info *fi)
 {
-       int (*proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
-               struct fuse_file_info *fi);
        char *error;
+       int (*__proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
+                             off_t offset, struct fuse_file_info *fi);
 
-       dlerror();    /* Clear any existing error */
-       proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_readdir");
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find proc_readdir()", error);
 
-       return proc_readdir(path, buf, filler, offset, fi);
+       return __proc_readdir(path, buf, filler, offset, fi);
 }
 
+static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                         off_t offset, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__sys_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
+                            off_t offset, struct fuse_file_info *fi);
+
+       dlerror();
+       __sys_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_readdir");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_readdir()", error);
+
+       return __sys_readdir(path, buf, filler, offset, fi);
+}
+
+
 static int do_cg_open(const char *path, struct fuse_file_info *fi)
 {
-       int (*cg_open)(const char *path, struct fuse_file_info *fi);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_open = (int (*)(const char *, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_open");
+       int (*__cg_open)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_open()", error);
+
+       return __cg_open(path, fi);
+}
+
+static int do_cg_access(const char *path, int mode)
+{
+       char *error;
+       int (*__cg_access)(const char *path, int mode);
 
-       return cg_open(path, fi);
+       dlerror();
+       __cg_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "cg_access");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_access()", error);
+
+       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);
        char *error;
-       dlerror();    /* Clear any existing error */
-       proc_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "proc_open");
+       int (*__proc_open)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find proc_open()", error);
+
+       return __proc_open(path, fi);
+}
+
+static int do_proc_access(const char *path, int mode)
+{
+       char *error;
+       int (*__proc_access)(const char *path, int mode);
+
+       dlerror();
+       __proc_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "proc_access");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find proc_access()", error);
+
+       return __proc_access(path, mode);
+}
+
+static int do_sys_open(const char *path, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__sys_open)(const char *path, struct fuse_file_info *fi);
 
-       return proc_open(path, fi);
+       dlerror();
+       __sys_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_open");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_open()", error);
+
+       return __sys_open(path, fi);
+}
+
+static int do_sys_access(const char *path, int mode)
+{
+       char *error;
+       int (*__sys_access)(const char *path, int mode);
+
+       dlerror();
+       __sys_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "sys_access");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_access()", error);
+
+       return __sys_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);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_release");
+       int (*__cg_release)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_release()", error);
 
-       return cg_release(path, fi);
+       return __cg_release(path, fi);
 }
 
 static int do_proc_release(const char *path, struct fuse_file_info *fi)
 {
-       int (*proc_release)(const char *path, struct fuse_file_info *fi);
        char *error;
-       dlerror();    /* Clear any existing error */
-       proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
+       int (*__proc_release)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find proc_release()", error);
 
-       return proc_release(path, fi);
+       return __proc_release(path, fi);
+}
+
+static int do_sys_release(const char *path, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__sys_release)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __sys_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_release");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_release()", error);
+
+       return __sys_release(path, fi);
 }
 
 static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
 {
-       int (*cg_opendir)(const char *path, struct fuse_file_info *fi);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "cg_opendir");
+       int (*__cg_opendir)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_opendir()", error);
 
-       return cg_opendir(path, fi);
+       return __cg_opendir(path, fi);
 }
 
 static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
 {
-       int (*cg_releasedir)(const char *path, struct fuse_file_info *fi);
        char *error;
-       dlerror();    /* Clear any existing error */
-       cg_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_releasedir");
+       int (*__cg_releasedir)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __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);
-               return -1;
-       }
+       if (error)
+               return log_error(-1, "%s - Failed to find cg_releasedir()", error);
 
-       return cg_releasedir(path, fi);
+       return __cg_releasedir(path, fi);
 }
 
-/*
- * FUSE ops for /
- * these just delegate to the /proc and /cgroup ops as
- * needed
- */
+static int do_sys_releasedir(const char *path, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__sys_releasedir)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __sys_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_releasedir");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_releasedir()", error);
+
+       return __sys_releasedir(path, 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);
                down_users();
                return ret;
        }
+
        if (strncmp(path, "/proc", 5) == 0) {
                up_users();
                ret = do_proc_getattr(path, sb);
                down_users();
                return ret;
        }
-       return -EINVAL;
+
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_getattr(path, sb);
+               down_users();
+               return ret;
+       }
+
+       return -ENOENT;
 }
 
 static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
 {
        int ret;
+
        if (strcmp(path, "/") == 0)
                return 0;
 
@@ -425,61 +617,125 @@ static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
                down_users();
                return ret;
        }
+
        if (strcmp(path, "/proc") == 0)
                return 0;
+
+       if (strncmp(path, "/sys", 4) == 0)
+               return 0;
+
        return -ENOENT;
 }
 
-static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
-               struct fuse_file_info *fi)
+static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                        off_t offset, struct fuse_file_info *fi)
 {
        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, "sys", NULL, 0) != 0 ||
+                   filler(buf, "cgroup", NULL, 0) != 0)
+                       return -ENOMEM;
+
                return 0;
        }
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_readdir(path, buf, filler, offset, fi);
                down_users();
                return ret;
        }
+
        if (strcmp(path, "/proc") == 0) {
                up_users();
                ret = do_proc_readdir(path, buf, filler, offset, fi);
                down_users();
                return ret;
        }
-       return -EINVAL;
+
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_readdir(path, buf, filler, offset, fi);
+               down_users();
+               return ret;
+       }
+
+       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;
+       }
+
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_access(path, mode);
+               down_users();
+               return ret;
+       }
+
+       return -EACCES;
 }
 
 static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
 {
        int ret;
+
        if (strcmp(path, "/") == 0)
                return 0;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_releasedir(path, fi);
                down_users();
                return ret;
        }
+
        if (strcmp(path, "/proc") == 0)
                return 0;
+
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_releasedir(path, fi);
+               down_users();
+               return ret;
+       }
+
        return -EINVAL;
 }
 
 static int lxcfs_open(const char *path, struct fuse_file_info *fi)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_open(path, fi);
                down_users();
                return ret;
        }
+
        if (strncmp(path, "/proc", 5) == 0) {
                up_users();
                ret = do_proc_open(path, fi);
@@ -487,19 +743,28 @@ static int lxcfs_open(const char *path, struct fuse_file_info *fi)
                return ret;
        }
 
-       return -EINVAL;
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_open(path, fi);
+               down_users();
+               return ret;
+       }
+
+       return -EACCES;
 }
 
 static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
-               struct fuse_file_info *fi)
+                     struct fuse_file_info *fi)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_read(path, buf, size, offset, fi);
                down_users();
                return ret;
        }
+
        if (strncmp(path, "/proc", 5) == 0) {
                up_users();
                ret = do_proc_read(path, buf, size, offset, fi);
@@ -507,13 +772,21 @@ static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
                return ret;
        }
 
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_read(path, buf, size, offset, fi);
+               down_users();
+               return ret;
+       }
+
        return -EINVAL;
 }
 
 int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
-            struct fuse_file_info *fi)
+               struct fuse_file_info *fi)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_write(path, buf, size, offset, fi);
@@ -532,12 +805,14 @@ static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
 static int lxcfs_release(const char *path, struct fuse_file_info *fi)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_release(path, fi);
                down_users();
                return ret;
        }
+
        if (strncmp(path, "/proc", 5) == 0) {
                up_users();
                ret = do_proc_release(path, fi);
@@ -545,6 +820,13 @@ static int lxcfs_release(const char *path, struct fuse_file_info *fi)
                return ret;
        }
 
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_release(path, fi);
+               down_users();
+               return ret;
+       }
+
        return -EINVAL;
 }
 
@@ -556,6 +838,7 @@ static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi
 int lxcfs_mkdir(const char *path, mode_t mode)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_mkdir(path, mode);
@@ -563,12 +846,13 @@ 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)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_chown(path, uid, gid);
@@ -576,7 +860,13 @@ int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
                return ret;
        }
 
-       return -EINVAL;
+       if (strncmp(path, "/proc", 5) == 0)
+               return -EPERM;
+
+       if (strncmp(path, "/sys", 4) == 0)
+               return -EPERM;
+
+       return -ENOENT;
 }
 
 /*
@@ -588,358 +878,323 @@ 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)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_rmdir(path);
                down_users();
                return ret;
        }
-       return -EINVAL;
+
+       return -EPERM;
 }
 
 int lxcfs_chmod(const char *path, mode_t mode)
 {
        int ret;
+
        if (strncmp(path, "/cgroup", 7) == 0) {
                up_users();
                ret = do_cg_chmod(path, mode);
                down_users();
                return ret;
        }
-       return -EINVAL;
+
+       if (strncmp(path, "/proc", 5) == 0)
+               return -EPERM;
+
+       if (strncmp(path, "/sys", 4) == 0)
+               return -EPERM;
+
+       return -ENOENT;
 }
 
 const struct fuse_operations lxcfs_ops = {
-       .getattr = lxcfs_getattr,
-       .readlink = NULL,
-       .getdir = NULL,
-       .mknod = NULL,
-       .mkdir = lxcfs_mkdir,
-       .unlink = NULL,
-       .rmdir = lxcfs_rmdir,
-       .symlink = NULL,
-       .rename = NULL,
-       .link = NULL,
-       .chmod = lxcfs_chmod,
-       .chown = lxcfs_chown,
-       .truncate = lxcfs_truncate,
-       .utime = NULL,
-
-       .open = lxcfs_open,
-       .read = lxcfs_read,
-       .release = lxcfs_release,
-       .write = lxcfs_write,
-
-       .statfs = NULL,
-       .flush = lxcfs_flush,
-       .fsync = lxcfs_fsync,
-
-       .setxattr = NULL,
-       .getxattr = NULL,
-       .listxattr = NULL,
-       .removexattr = NULL,
-
-       .opendir = lxcfs_opendir,
-       .readdir = lxcfs_readdir,
-       .releasedir = lxcfs_releasedir,
-
-       .fsyncdir = NULL,
-       .init = NULL,
-       .destroy = NULL,
-       .access = NULL,
-       .create = NULL,
-       .ftruncate = NULL,
-       .fgetattr = NULL,
+       .access         = lxcfs_access,
+       .chmod          = lxcfs_chmod,
+       .chown          = lxcfs_chown,
+       .flush          = lxcfs_flush,
+       .fsync          = lxcfs_fsync,
+       .getattr        = lxcfs_getattr,
+       .mkdir          = lxcfs_mkdir,
+       .open           = lxcfs_open,
+       .opendir        = lxcfs_opendir,
+       .read           = lxcfs_read,
+       .readdir        = lxcfs_readdir,
+       .release        = lxcfs_release,
+       .releasedir     = lxcfs_releasedir,
+       .rmdir          = lxcfs_rmdir,
+       .truncate       = lxcfs_truncate,
+       .write          = lxcfs_write,
+
+       .create         = NULL,
+       .destroy        = NULL,
+       .fgetattr       = NULL,
+       .fsyncdir       = NULL,
+       .ftruncate      = NULL,
+       .getdir         = NULL,
+       .getxattr       = NULL,
+       .init           = NULL,
+       .link           = NULL,
+       .listxattr      = NULL,
+       .mknod          = NULL,
+       .readlink       = NULL,
+       .rename         = NULL,
+       .removexattr    = NULL,
+       .setxattr       = NULL,
+       .statfs         = NULL,
+       .symlink        = NULL,
+       .unlink         = NULL,
+       .utime          = NULL,
 };
 
-static void usage(const char *me)
+static void usage()
 {
-       fprintf(stderr, "Usage:\n");
+       fprintf(stderr, "Usage: lxcfs <directory>\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "lxcfs set up fuse- and cgroup-based virtualizing filesystem\n");
        fprintf(stderr, "\n");
-       fprintf(stderr, "%s [-p pidfile] mountpoint\n", me);
-       fprintf(stderr, "  Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
-       fprintf(stderr, "%s -h\n", me);
-       exit(1);
+       fprintf(stderr, "Options :\n");
+       fprintf(stderr, "-d, --debug            Run lxcfs with debugging enabled\n");
+       fprintf(stderr, "--disable-cfs          Disable cpu virtualization via cpu shares\n");
+       fprintf(stderr, "-f, --foreground       Run lxcfs in the foreground\n");
+       fprintf(stderr, "-n, --help             Print help\n");
+       fprintf(stderr, "-l, --enable-loadavg   Enable loadavg virtualization\n");
+       fprintf(stderr, "-o                     Options to pass directly through fuse\n");
+       fprintf(stderr, "-p, --pidfile=FILE     Path to use for storing lxcfs pid\n");
+       fprintf(stderr, "                       Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
+       fprintf(stderr, "-u, --disable-swap     Disable swap virtualization\n");
+       fprintf(stderr, "-v, --version          Print lxcfs version\n");
+       fprintf(stderr, "--enable-pidfd         Use pidfd for process tracking\n");
+       exit(EXIT_FAILURE);
 }
 
-static bool is_help(char *w)
+static inline bool is_help(char *w)
 {
-       if (strcmp(w, "-h") == 0 ||
-                       strcmp(w, "--help") == 0 ||
-                       strcmp(w, "-help") == 0 ||
-                       strcmp(w, "help") == 0)
-               return true;
-       return false;
+       return strcmp(w, "-h") == 0 ||
+              strcmp(w, "--help") == 0 ||
+              strcmp(w, "-help") == 0 ||
+              strcmp(w, "help") == 0;
 }
 
-void swallow_arg(int *argcp, char *argv[], char *which)
+static inline bool is_version(char *w)
 {
-       int i;
+       return strcmp(w, "-v") == 0 ||
+              strcmp(w, "--version") == 0 ||
+              strcmp(w, "-version") == 0 ||
+              strcmp(w, "version") == 0;
+}
 
-       for (i = 1; argv[i]; i++) {
+static bool swallow_arg(int *argcp, char *argv[], char *which)
+{
+       for (int i = 1; argv[i]; i++) {
                if (strcmp(argv[i], which) != 0)
                        continue;
-               for (; argv[i]; i++) {
-                       argv[i] = argv[i+1];
-               }
+
+               for (; argv[i]; i++)
+                       argv[i] = argv[i + 1];
+
                (*argcp)--;
-               return;
+               return true;
        }
+
+       return false;
 }
 
-bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
+static bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
 {
-       int i;
-
-       for (i = 1; argv[i]; i++) {
-               if (!argv[i+1])
+       for (int i = 1; argv[i]; i++) {
+               if (!argv[i + 1])
                        continue;
+
                if (strcmp(argv[i], opt) != 0)
                        continue;
+
                do {
-                       *v = strdup(argv[i+1]);
+                       *v = strdup(argv[i + 1]);
                } while (!*v);
-               for (; argv[i+1]; i++) {
-                       argv[i] = argv[i+2];
-               }
-               (*argcp) -= 2;
-               return true;
-       }
-       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;
-}
+               for (; argv[i + 1]; i++)
+                       argv[i] = argv[i + 2];
 
-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;
+               (*argcp) -= 2;
+               return true;
        }
-       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;
+       return false;
 }
 
-static bool do_mount_cgroup(char *controller)
+static int set_pidfile(char *pidfile)
 {
-       char *target;
-       size_t len;
+       __do_close_prot_errno int fd = -EBADF;
+       char buf[INTTYPE_TO_STRLEN(long)];
        int ret;
+       struct flock fl = {
+               fl.l_type       = F_WRLCK,
+               fl.l_whence     = SEEK_SET,
+               fl.l_start      = 0,
+               fl.l_len        = 0,
+       };
 
-       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;
+       fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+       if (fd < 0)
+               return log_error(-1, "Could not open pidfile %s: %m", pidfile);
 
-       if ((f = fopen("/proc/self/cgroup", "r")) == NULL) {
-               fprintf(stderr, "Error opening /proc/self/cgroup: %s\n", strerror(errno));
-               return false;
+       if (fcntl(fd, F_SETLK, &fl) < 0) {
+               if (errno == EAGAIN || errno == EACCES)
+                       return log_error(-1, "PID file '%s' is already locked", pidfile);
+               lxcfs_error("Warning; unable to lock PID file, proceeding");
        }
 
-       while (getline(&line, &len, f) != -1) {
-               char *p, *p2;
+       if (ftruncate(fd, 0))
+               return log_error(-1, "Error truncating PID file '%s': %m", pidfile);
 
-               p = strchr(line, ':');
-               if (!p)
-                       goto out;
-               *(p++) = '\0';
+       ret = snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());
+       if (ret < 0 || ret >= sizeof(buf))
+               return log_error(-1, "Failed to convert pid to string %m");
 
-               p2 = strrchr(p, ':');
-               if (!p2)
-                       goto out;
-               *p2 = '\0';
+       if (write(fd, buf, ret) != ret)
+               return log_error(-1, "Error writing to PID file '%s': %m", pidfile);
 
-               if (!do_mount_cgroup(p))
-                       goto out;
-       }
-       ret = true;
-
-out:
-       free(line);
-       fclose(f);
-       return ret;
+       return move_fd(fd);
 }
 
-static bool cgfs_setup_controllers(void)
+int main(int argc, char *argv[])
 {
-       if (!setup_cgfs_dir()) {
-               return false;
-       }
+       __do_close_prot_errno int pidfile_fd = -EBADF;
+       int ret = EXIT_FAILURE;
+       char *pidfile = NULL, *saveptr = NULL, *token = NULL, *v = NULL;
+       char pidfile_buf[STRLITERALLEN(RUNTIME_PATH) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
+       bool debug = false, foreground = false, nonempty = false;
+       bool load_use = false;
+       /*
+        * what we pass to fuse_main is:
+        * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
+        */
+       int nargs = 5, cnt = 0;
+       char *newargv[6];
+       struct lxcfs_opts *opts;
 
-       if (!do_mount_cgroups()) {
-               fprintf(stderr, "Failed to set up cgroup mounts\n");
-               return false;
+       opts = malloc(sizeof(struct lxcfs_opts));
+       if (opts == NULL) {
+               lxcfs_error("Error allocating memory for options");
+               goto out;
        }
+       opts->swap_off = false;
+       opts->use_pidfd = false;
+       opts->use_cfs = true;
 
-       return true;
-}
+       /* accomodate older init scripts */
+       swallow_arg(&argc, argv, "-s");
 
-static int set_pidfile(char *pidfile)
-{
-       int fd;
-       char buf[50];
-       struct flock fl;
+       /* -f / --foreground */
+       foreground = swallow_arg(&argc, argv, "-f");
+       if (swallow_arg(&argc, argv, "--foreground"))
+               foreground = true;
 
-       fl.l_type = F_WRLCK;
-       fl.l_whence = SEEK_SET;
-       fl.l_start = 0;
-       fl.l_len = 0;
+       /* -d / --debug */
+       debug = swallow_arg(&argc, argv, "-d");
+       if (swallow_arg(&argc, argv, "--debug"))
+               debug = true;
 
-       fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
-       if (fd == -1) {
-               fprintf(stderr, "Could not open pidfile %s: %m", pidfile);
-               return -1;
-       }
+       if (foreground && debug)
+               log_exit("Both --debug and --forgreound specified");
 
-       if (fcntl(fd, F_SETLK, &fl) == -1) {
-               if (errno  == EAGAIN || errno == EACCES) {
-                       fprintf(stderr, "PID file '%s' is already locked.\n", pidfile);
-                       close(fd);
-                       return -1;
-               }
-               fprintf(stderr, "Warning; unable to lock PID file, proceeding.\n");
-       }
+       /* -l / --enable-loadavg */
+       load_use = swallow_arg(&argc, argv, "-l");
+       if (swallow_arg(&argc, argv, "--enable-loadavg"))
+               load_use = true;
 
-       if (ftruncate(fd, 0) == -1) {
-               fprintf(stderr, "Error truncating PID file '%s': %m", pidfile);
-               close(fd);
-               return -1;
-       }
+       /* -u / --disable-swap */
+       opts->swap_off = swallow_arg(&argc, argv, "-u");
+       if (swallow_arg(&argc, argv, "--disable-swap"))
+               opts->swap_off = true;
 
-       snprintf(buf, 50, "%ld\n", (long) getpid());
-       if (write(fd, buf, strlen(buf)) != strlen(buf)) {
-               fprintf(stderr, "Error writing to PID file '%s': %m", pidfile);
-               close(fd);
-               return -1;
-       }
+       /* --enable-pidfd */
+       opts->use_pidfd = swallow_arg(&argc, argv, "--enable-pidfd");
 
-       return fd;
-}
+       /* --disable-cfs */
+       if (swallow_arg(&argc, argv, "--disable-cfs"))
+               opts->use_cfs = false;
 
-int main(int argc, char *argv[])
-{
-       int ret = -1, pidfd;
-       char *pidfile = NULL, *v = NULL;
-       size_t pidfile_len;
-       /*
-        * what we pass to fuse_main is:
-        * argv[0] -s -f -o allow_other,directio argv[1] NULL
-        */
-       int nargs = 5, cnt = 0;
-       char *newargv[6];
-
-       /* accomodate older init scripts */
-       swallow_arg(&argc, argv, "-s");
-       swallow_arg(&argc, argv, "-f");
        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);
+                               lxcfs_error("Warning: unexpected fuse option %s", v);
+                               exit(EXIT_FAILURE);
+                       }
                }
                free(v);
                v = NULL;
        }
+
+       /* -p / --pidfile */
        if (swallow_option(&argc, argv, "-p", &v))
                pidfile = v;
+       if (!pidfile && swallow_option(&argc, argv, "--pidfile", &v))
+               pidfile = v;
 
-       if (argc == 2  && strcmp(argv[1], "--version") == 0) {
+       if (argc == 2  && is_version(argv[1])) {
                fprintf(stderr, "%s\n", VERSION);
-               exit(0);
+               exit(EXIT_SUCCESS);
        }
+
        if (argc != 2 || is_help(argv[1]))
-               usage(argv[0]);
+               usage();
 
        do_reload();
        if (signal(SIGUSR1, reload_handler) == SIG_ERR) {
-               fprintf(stderr, "Error loading USR1 signal handler: %m\n");
-               exit(1);
+               lxcfs_error("Error setting USR1 signal handler: %m");
+               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++] = "default_permissions,allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
+       else
+               newargv[cnt++] = "default_permissions,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);
-               snprintf(pidfile, pidfile_len, "%s/lxcfs.pid", RUNTIME_PATH);
+               snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH);
+               pidfile = pidfile_buf;
        }
-       if ((pidfd = set_pidfile(pidfile)) < 0)
+
+       pidfile_fd = set_pidfile(pidfile);
+       if (pidfile_fd < 0)
                goto out;
 
-       ret = fuse_main(nargs, newargv, &lxcfs_ops, NULL);
+       if (load_use && start_loadavg() != 0)
+               goto out;
 
-       dlclose(dlopen_handle);
-       unlink(pidfile);
-       close(pidfd);
+       if (!fuse_main(nargs, newargv, &lxcfs_ops, opts))
+               ret = EXIT_SUCCESS;
+       if (load_use)
+               stop_loadavg();
 
 out:
-       return ret;
+       if (dlopen_handle)
+               dlclose(dlopen_handle);
+       if (pidfile)
+               unlink(pidfile);
+       exit(ret);
 }