* 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;
{
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;
}
/* 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;
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);
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);
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);
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);
return ret;
}
+ if (strncmp(path, "/sys", 4) == 0) {
+ up_users();
+ ret = do_sys_release(path, fi);
+ down_users();
+ return ret;
+ }
+
return -EINVAL;
}
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);
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);
return ret;
}
- return -EINVAL;
+ if (strncmp(path, "/proc", 5) == 0)
+ return -EPERM;
+
+ if (strncmp(path, "/sys", 4) == 0)
+ return -EPERM;
+
+ return -ENOENT;
}
/*
{
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);
}