-/* lxcfs
- *
- * Copyright © 2014-2016 Canonical, Inc
- * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
- *
- * See COPYING file for details.
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
+/* SPDX-License-Identifier: LGPL-2.1+ */
-#ifndef FUSE_USE_VERSION
-#define FUSE_USE_VERSION 26
-#endif
-
-#define _FILE_OFFSET_BITS 64
+#include "config.h"
#include <alloca.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
-#include <fuse.h>
+#include <getopt.h>
+#include <inttypes.h>
#include <libgen.h>
#include <pthread.h>
#include <sched.h>
#include <sys/socket.h>
#include <linux/limits.h>
+#include "lxcfs_fuse.h"
+
#include "bindings.h"
-#include "config.h"
+#include "lxcfs_fuse_compat.h"
#include "macro.h"
#include "memory_utils.h"
unlock_mutex(&user_count_mutex);
}
+/* Returns file info type of custom type declaration carried
+ * in fuse_file_info */
+static inline enum lxcfs_virt_t file_info_type(struct fuse_file_info *fi)
+{
+ struct file_info *f;
+
+ f = INTTYPE_TO_PTR(fi->fh);
+ if (!f)
+ return -1;
+
+ if (!LXCFS_TYPE_OK(f->type))
+ return -1;
+
+ return f->type;
+}
+
static pthread_t loadavg_pid = 0;
/* Returns zero on success */
static volatile sig_atomic_t need_reload;
+static int lxcfs_init_library(void)
+{
+ char *error;
+ void *(*__lxcfs_fuse_init)(struct fuse_conn_info * conn, void * cfg);
+
+ dlerror();
+ __lxcfs_fuse_init = (void *(*)(struct fuse_conn_info * conn, void * cfg))dlsym(dlopen_handle, "lxcfs_fuse_init");
+ error = dlerror();
+ if (error)
+ return log_error(-1, "%s - Failed to find lxcfs_fuse_init()", error);
+
+ __lxcfs_fuse_init(NULL, NULL);
+
+ return 0;
+}
+
/* do_reload - reload the dynamic library. Done under
* lock and when we know the user_count was 0 */
-static void do_reload(void)
+static void do_reload(bool reinit)
{
int ret;
char lxcfs_lib_path[PATH_MAX];
}
/* First try loading using ld.so */
+#ifdef RESOLVE_NOW
+ dlopen_handle = dlopen("liblxcfs.so", RTLD_NOW);
+#else
dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
+#endif
if (dlopen_handle) {
lxcfs_debug("Opened liblxcfs.so");
goto good;
#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))
+ if (ret < 0 || (size_t)ret >= sizeof(lxcfs_lib_path))
log_exit("Failed to create path to open liblxcfs");
dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY);
lxcfs_debug("Opened %s", lxcfs_lib_path);
good:
+ /* initialize the library */
+ if (reinit && lxcfs_init_library() < 0) {
+ log_exit("Failed to initialize liblxcfs.so");
+ }
+
if (loadavg_pid > 0)
start_loadavg();
{
users_lock();
if (users_count == 0 && need_reload)
- do_reload();
+ do_reload(true);
users_count++;
users_unlock();
}
users_unlock();
}
-static void reload_handler(int sig)
+static void sigusr1_reload(int signo, siginfo_t *info, void *extra)
{
need_reload = 1;
}
return __cg_write(path, buf, size, offset, fi);
}
+static int do_sys_write(const char *path, const char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi)
+{
+ char *error;
+ int (*__sys_write)(const char *path, const char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi);
+
+ dlerror();
+ __sys_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_write");
+ error = dlerror();
+ if (error)
+ return log_error(-1, "%s - Failed to find sys_write()", error);
+
+ return __sys_write(path, buf, size, offset, fi);
+}
+
static int do_cg_mkdir(const char *path, mode_t mode)
{
char *error;
return __sys_readdir(path, buf, filler, offset, fi);
}
+static int do_sys_readlink(const char *path, char *buf, size_t size)
+{
+ char *error;
+ int (*__sys_readlink)(const char *path, char *buf, size_t size);
+
+ dlerror();
+ __sys_readlink = (int (*)(const char *, char *, size_t))dlsym(dlopen_handle, "sys_readlink");
+ error = dlerror();
+ if (error)
+ return log_error(-1, "%s - Failed to find sys_readlink()", error);
+
+ return __sys_readlink(path, buf, size);
+}
static int do_cg_open(const char *path, struct fuse_file_info *fi)
{
return __sys_open(path, fi);
}
+static int do_sys_opendir(const char *path, struct fuse_file_info *fi)
+{
+ char *error;
+ int (*__sys_opendir)(const char *path, struct fuse_file_info *fi);
+
+ dlerror();
+ __sys_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_opendir");
+ error = dlerror();
+ if (error)
+ return log_error(-1, "%s - Failed to find sys_opendir()", error);
+
+ return __sys_opendir(path, fi);
+}
+
static int do_sys_access(const char *path, int mode)
{
char *error;
return __sys_releasedir(path, fi);
}
+#if HAVE_FUSE3
+static int lxcfs_getattr(const char *path, struct stat *sb, struct fuse_file_info *fi)
+#else
static int lxcfs_getattr(const char *path, struct stat *sb)
+#endif
{
int ret;
struct timespec now;
if (strcmp(path, "/proc") == 0)
return 0;
- if (strncmp(path, "/sys", 4) == 0)
- return 0;
+ if (strncmp(path, "/sys", 4) == 0) {
+ up_users();
+ ret = do_sys_opendir(path, fi);
+ down_users();
+ return ret;
+ }
return -ENOENT;
}
+#if HAVE_FUSE3
+static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
+#else
static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
+#endif
{
int ret;
if (strcmp(path, "/") == 0) {
- 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)
+ if (dir_filler(filler, buf, ".", 0) != 0 ||
+ dir_filler(filler, buf, "..", 0) != 0 ||
+ dir_filler(filler, buf, "proc", 0) != 0 ||
+ dir_filler(filler, buf, "sys", 0) != 0 ||
+ dir_filler(filler, buf, "cgroup", 0) != 0)
return -ENOMEM;
return 0;
static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
{
int ret;
+ enum lxcfs_virt_t type;
- if (strcmp(path, "/") == 0)
- return 0;
+ type = file_info_type(fi);
- if (strncmp(path, "/cgroup", 7) == 0) {
+ if (LXCFS_TYPE_CGROUP(type)) {
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) {
+ if (LXCFS_TYPE_SYS(type)) {
up_users();
ret = do_sys_releasedir(path, fi);
down_users();
return ret;
}
+ if (path) {
+ if (strcmp(path, "/") == 0)
+ return 0;
+ if (strcmp(path, "/proc") == 0)
+ return 0;
+ }
+
+ lxcfs_error("unknown file type: path=%s, type=%d, fi->fh=%" PRIu64,
+ path, type, fi->fh);
+
return -EINVAL;
}
return ret;
}
+ if (strncmp(path, "/sys", 4) == 0) {
+ up_users();
+ ret = do_sys_write(path, buf, size, offset, fi);
+ down_users();
+ return ret;
+ }
+
+ return -EINVAL;
+}
+
+int lxcfs_readlink(const char *path, char *buf, size_t size)
+{
+ int ret;
+
+ if (strncmp(path, "/sys", 4) == 0) {
+ up_users();
+ ret = do_sys_readlink(path, buf, size);
+ down_users();
+ return ret;
+ }
+
return -EINVAL;
}
static int lxcfs_release(const char *path, struct fuse_file_info *fi)
{
int ret;
+ enum lxcfs_virt_t type;
- if (strncmp(path, "/cgroup", 7) == 0) {
+ type = file_info_type(fi);
+
+ if (LXCFS_TYPE_CGROUP(type)) {
up_users();
ret = do_cg_release(path, fi);
down_users();
return ret;
}
- if (strncmp(path, "/proc", 5) == 0) {
+ if (LXCFS_TYPE_PROC(type)) {
up_users();
ret = do_proc_release(path, fi);
down_users();
return ret;
}
- if (strncmp(path, "/sys", 4) == 0) {
+ if (LXCFS_TYPE_SYS(type)) {
up_users();
ret = do_sys_release(path, fi);
down_users();
return ret;
}
+ lxcfs_error("unknown file type: path=%s, type=%d, fi->fh=%" PRIu64,
+ path, type, fi->fh);
+
return -EINVAL;
}
return -EPERM;
}
+#if HAVE_FUSE3
+int lxcfs_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi)
+#else
int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
+#endif
{
int ret;
* really make sense for cgroups. So just return 0 always but do
* nothing.
*/
+#if HAVE_FUSE3
+int lxcfs_truncate(const char *path, off_t newsize, struct fuse_file_info *fi)
+#else
int lxcfs_truncate(const char *path, off_t newsize)
+#endif
{
if (strncmp(path, "/cgroup", 7) == 0)
return 0;
+ if (strncmp(path, "/sys", 4) == 0)
+ return 0;
+
return -EPERM;
}
return -EPERM;
}
+#if HAVE_FUSE3
+int lxcfs_chmod(const char *path, mode_t mode, struct fuse_file_info *fi)
+#else
int lxcfs_chmod(const char *path, mode_t mode)
+#endif
{
int ret;
return -ENOENT;
}
+#if HAVE_FUSE3
+static void *lxcfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
+#else
+static void *lxcfs_init(struct fuse_conn_info *conn)
+#endif
+{
+ if (lxcfs_init_library() < 0)
+ return NULL;
+
+#if HAVE_FUSE3
+ cfg->direct_io = 1;
+#endif
+
+ return fuse_get_context()->private_data;
+}
+
const struct fuse_operations lxcfs_ops = {
.access = lxcfs_access,
.chmod = lxcfs_chmod,
.flush = lxcfs_flush,
.fsync = lxcfs_fsync,
.getattr = lxcfs_getattr,
+ .init = lxcfs_init,
.mkdir = lxcfs_mkdir,
.open = lxcfs_open,
.opendir = lxcfs_opendir,
.rmdir = lxcfs_rmdir,
.truncate = lxcfs_truncate,
.write = lxcfs_write,
+ .readlink = lxcfs_readlink,
.create = NULL,
.destroy = NULL,
+#if !HAVE_FUSE3
.fgetattr = NULL,
+#endif
.fsyncdir = NULL,
+#if !HAVE_FUSE3
.ftruncate = NULL,
.getdir = NULL,
+#endif
.getxattr = NULL,
- .init = NULL,
.link = NULL,
.listxattr = NULL,
.mknod = NULL,
- .readlink = NULL,
.rename = NULL,
.removexattr = NULL,
.setxattr = NULL,
.statfs = NULL,
.symlink = NULL,
.unlink = NULL,
+#if !HAVE_FUSE3
.utime = NULL,
+#endif
};
-static void usage()
+static void usage(void)
{
lxcfs_info("Usage: lxcfs <directory>\n");
- lxcfs_info("lxcfs set up fuse- and cgroup-based virtualizing filesystem\n");
+ lxcfs_info("lxcfs is a FUSE-based proc, sys and cgroup virtualizing filesystem\n");
lxcfs_info("Options :");
- lxcfs_info("-d, --debug Run lxcfs with debugging enabled");
- lxcfs_info("--disable-cfs Disable cpu virtualization via cpu shares");
- lxcfs_info("-f, --foreground Run lxcfs in the foreground");
- lxcfs_info("-n, --help Print help");
- lxcfs_info("-l, --enable-loadavg Enable loadavg virtualization");
- lxcfs_info("-o Options to pass directly through fuse");
- lxcfs_info("-p, --pidfile=FILE Path to use for storing lxcfs pid");
- lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH);
- lxcfs_info("-u, --disable-swap Disable swap virtualization");
- lxcfs_info("-v, --version Print lxcfs version");
- lxcfs_info("--enable-pidfd Use pidfd for process tracking");
+ lxcfs_info(" -d, --debug Run lxcfs with debugging enabled");
+ lxcfs_info(" -f, --foreground Run lxcfs in the foreground");
+ lxcfs_info(" -n, --help Print help");
+ lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization");
+ lxcfs_info(" -o Options to pass directly through fuse");
+ lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid");
+ lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH);
+ lxcfs_info(" -u, --disable-swap Disable swap virtualization");
+ lxcfs_info(" -v, --version Print lxcfs version");
+ lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares");
+ lxcfs_info(" --enable-pidfd Use pidfd for process tracking");
exit(EXIT_FAILURE);
}
-static inline bool is_help(char *w)
-{
- return strcmp(w, "-h") == 0 ||
- strcmp(w, "--help") == 0 ||
- strcmp(w, "-help") == 0 ||
- strcmp(w, "help") == 0;
-}
-
-static inline bool is_version(char *w)
-{
- return strcmp(w, "-v") == 0 ||
- strcmp(w, "--version") == 0 ||
- strcmp(w, "-version") == 0 ||
- strcmp(w, "version") == 0;
-}
-
-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];
-
- (*argcp)--;
- return true;
- }
-
- return false;
-}
-
-static bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
-{
- 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]);
- } while (!*v);
-
- for (; argv[i + 1]; i++)
- argv[i] = argv[i + 2];
-
- (*argcp) -= 2;
- return true;
- }
-
- return false;
-}
-
static int set_pidfile(char *pidfile)
{
- __do_close_prot_errno int fd = -EBADF;
+ __do_close 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,
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0,
};
- fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | O_CLOEXEC);
if (fd < 0)
return log_error(-1, "Could not open pidfile %s: %m", pidfile);
return log_error(-1, "Error truncating PID file '%s': %m", pidfile);
ret = snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());
- if (ret < 0 || ret >= sizeof(buf))
+ if (ret < 0 || (size_t)ret >= sizeof(buf))
return log_error(-1, "Failed to convert pid to string %m");
if (write(fd, buf, ret) != ret)
return move_fd(fd);
}
+static const struct option long_options[] = {
+ {"debug", no_argument, 0, 'd' },
+ {"disable-swap", no_argument, 0, 'u' },
+ {"enable-loadavg", no_argument, 0, 'l' },
+ {"foreground", no_argument, 0, 'f' },
+ {"help", no_argument, 0, 'h' },
+ {"version", no_argument, 0, 'v' },
+
+ {"enable-cfs", no_argument, 0, 0 },
+ {"enable-pidfd", no_argument, 0, 0 },
+
+ {"pidfile", required_argument, 0, 'p' },
+ { },
+};
+
+static int append_comma_separate(char **s, const char *append)
+{
+ int ret;
+ char *news;
+ size_t append_len, len;
+
+ if (!append)
+ return 0;
+
+ append_len = strlen(append);
+ if (!append_len)
+ return 0;
+
+ if (*s) {
+ len = strlen(*s);
+ news = realloc(*s, len + append_len + 2);
+ } else {
+ len = 0;
+ news = realloc(NULL, append_len + 1);
+ }
+ if (!news)
+ return -ENOMEM;
+
+ if (*s)
+ ret = snprintf(news + len, append_len + 2, ",%s", append);
+ else
+ ret = snprintf(news, append_len + 1, "%s", append);
+ if (ret < 0)
+ return -EIO;
+
+ *s = news;
+ return 0;
+}
+
int main(int argc, char *argv[])
{
- __do_close_prot_errno int pidfile_fd = -EBADF;
+ int pidfile_fd = -EBADF;
int ret = EXIT_FAILURE;
- char *pidfile = NULL, *saveptr = NULL, *token = NULL, *v = NULL;
+ char *pidfile = NULL, *token = NULL;
char pidfile_buf[STRLITERALLEN(RUNTIME_PATH) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
- bool debug = false, foreground = false, nonempty = false;
+ bool debug = false, foreground = false;
+#if !HAVE_FUSE3
+ bool nonempty = false;
+#endif
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];
+ int fuse_argc = 0;
+ int c, idx, new_argc;
+ char *fuse_argv[7];
+ const char *fuse_opts = NULL;
+ char *new_fuse_opts = NULL;
+ char *const *new_argv;
struct lxcfs_opts *opts;
opts = malloc(sizeof(struct lxcfs_opts));
lxcfs_error("Error allocating memory for options");
goto out;
}
+
opts->swap_off = false;
opts->use_pidfd = false;
- opts->use_cfs = true;
-
- /* accomodate older init scripts */
- swallow_arg(&argc, argv, "-s");
-
- /* -f / --foreground */
- foreground = swallow_arg(&argc, argv, "-f");
- if (swallow_arg(&argc, argv, "--foreground"))
- foreground = true;
+ opts->use_cfs = false;
+ opts->version = 1;
+
+ while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) {
+ switch (c) {
+ case 0:
+ if (strcmp(long_options[idx].name, "enable-pidfd") == 0)
+ opts->use_pidfd = true;
+ else if (strcmp(long_options[idx].name, "enable-cfs") == 0)
+ opts->use_cfs = true;
+ else
+ usage();
+ break;
+ case 'd':
+ debug = true;
+ break;
+ case 'f':
+ foreground = true;
+ break;
+ case 'l':
+ load_use = true;
+ break;
+ case 'o':
+ if (fuse_opts) {
+ lxcfs_error("Specifying -o multiple times is unsupported");
+ usage();
+ }
- /* -d / --debug */
- debug = swallow_arg(&argc, argv, "-d");
- if (swallow_arg(&argc, argv, "--debug"))
- debug = true;
+ fuse_opts = optarg;
+ break;
+ case 'p':
+ pidfile = optarg;
+ break;
+ case 's':
+ /* legacy argument: ignore */
+ break;
+ case 'u':
+ opts->swap_off = true;
+ break;
+ case 'v':
+ lxcfs_info("%s", STRINGIFY(PROJECT_VERSION));
+ exit(EXIT_SUCCESS);
+ default:
+ usage();
+ }
+ }
if (foreground && debug)
log_exit("Both --debug and --forgreound specified");
- /* -l / --enable-loadavg */
- load_use = swallow_arg(&argc, argv, "-l");
- if (swallow_arg(&argc, argv, "--enable-loadavg"))
- load_use = true;
-
- /* -u / --disable-swap */
- opts->swap_off = swallow_arg(&argc, argv, "-u");
- if (swallow_arg(&argc, argv, "--disable-swap"))
- opts->swap_off = true;
-
- /* --enable-pidfd */
- opts->use_pidfd = swallow_arg(&argc, argv, "--enable-pidfd");
-
- /* --disable-cfs */
- if (swallow_arg(&argc, argv, "--disable-cfs"))
- opts->use_cfs = false;
-
- if (swallow_option(&argc, argv, "-o", &v)) {
- /* 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) {
+ new_argv = &argv[optind];
+ new_argc = argc - optind;
+
+ /* Older LXCFS versions printed help when used without any argument. */
+ if (new_argc == 0)
+ usage();
+
+ if (new_argc != 1) {
+ lxcfs_error("Missing mountpoint");
+ goto out;
+ }
+
+ fuse_argv[fuse_argc++] = argv[0];
+ if (debug)
+ fuse_argv[fuse_argc++] = "-d";
+ else
+ fuse_argv[fuse_argc++] = "-f";
+ fuse_argv[fuse_argc++] = "-o";
+
+ /* Parse additional fuse options. */
+ if (fuse_opts) {
+ char *dup;
+
+ dup = strdup(fuse_opts);
+ if (!dup) {
+ lxcfs_error("Failed to copy fuse options");
+ goto out;
+ }
+
+ lxc_iterate_parts(token, dup, ",") {
+ /* default */
+ if (strcmp(token, "allow_other") == 0)
+ continue;
+
+ /* default for LXCFS */
+ if (strcmp(token, "direct_io") == 0)
+ continue;
+
+ /* default for LXCFS */
+ if (strncmp(token, "entry_timeout", STRLITERALLEN("entry_timeout")) == 0)
+ continue;
+
+ /* default for LXCFS */
+ if (strncmp(token, "attr_timeout", STRLITERALLEN("entry_timeout")) == 0)
+ continue;
+
+ /* default for LXCFS */
+ if (strncmp(token, "allow_other", STRLITERALLEN("allow_other")) == 0)
+ continue;
+
+ /* default with fuse3 */
+ if (strcmp(token, "nonempty") == 0) {
+ #if !HAVE_FUSE3
nonempty = true;
- } else {
- free(v);
- lxcfs_error("Warning: unexpected fuse option %s", v);
- exit(EXIT_FAILURE);
+ #endif
+ continue;
+ }
+
+ if (append_comma_separate(&new_fuse_opts, token)) {
+ lxcfs_error("Failed to copy fuse argument \"%s\"", token);
+ free(dup);
+ goto out;
}
}
- free(v);
- v = NULL;
+ free(dup);
}
- /* -p / --pidfile */
- if (swallow_option(&argc, argv, "-p", &v))
- pidfile = v;
- if (!pidfile && swallow_option(&argc, argv, "--pidfile", &v))
- pidfile = v;
-
- if (argc == 2 && is_version(argv[1])) {
- lxcfs_info("%s", VERSION);
- exit(EXIT_SUCCESS);
+ if (append_comma_separate(&new_fuse_opts, "allow_other,entry_timeout=0.5,attr_timeout=0.5")) {
+ lxcfs_error("Failed to copy fuse argument \"allow_other,entry_timeout=0.5,attr_timeout=0.5\"");
+ goto out;
}
- if (argc != 2 || is_help(argv[1]))
- usage();
+#if !HAVE_FUSE3
+ if (nonempty) {
+ if (append_comma_separate(&new_fuse_opts, "nonempty")) {
+ lxcfs_error("Failed to copy fuse argument \"nonempty\"");
+ goto out;
+ }
+ }
- do_reload();
- if (signal(SIGUSR1, reload_handler) == SIG_ERR) {
- lxcfs_error("Error setting USR1 signal handler: %m");
+ if (append_comma_separate(&new_fuse_opts, "direct_io")) {
+ lxcfs_error("Failed to copy fuse argument \"direct_io\"");
goto out;
}
+#endif
- newargv[cnt++] = argv[0];
- if (debug)
- newargv[cnt++] = "-d";
- else
- newargv[cnt++] = "-f";
- newargv[cnt++] = "-o";
- 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;
+ /*
+ * We can't use default_permissions since we still support systems that
+ * don't have kernels with cgroup namespace support. On such kernels
+ * lxcfs will provide a namespaced cgroup view and needs explicit
+ * access helpers to make that work.
+ * Another reason that came to me is that we can't or at least
+ * shouldn't guarantee that we don't need more complicated access
+ * helpers for proc and sys virtualization in the future.
+ */
+
+ fuse_argv[fuse_argc++] = new_fuse_opts;
+ fuse_argv[fuse_argc++] = new_argv[0];
+ fuse_argv[fuse_argc] = NULL;
+
+ do_reload(false);
+ if (install_signal_handler(SIGUSR1, sigusr1_reload)) {
+ lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno));
+ goto out;
+ }
if (!pidfile) {
snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH);
if (load_use && start_loadavg() != 0)
goto out;
- if (!fuse_main(nargs, newargv, &lxcfs_ops, opts))
+ if (!fuse_main(fuse_argc, fuse_argv, &lxcfs_ops, opts))
ret = EXIT_SUCCESS;
+
if (load_use)
stop_loadavg();
dlclose(dlopen_handle);
if (pidfile)
unlink(pidfile);
+ free(new_fuse_opts);
+ free(opts);
+ close_prot_errno_disarm(pidfile_fd);
exit(ret);
}