diff --git a/meson.build b/meson.build index edc642c6..68787738 100644 --- a/meson.build +++ b/meson.build @@ -57,7 +57,7 @@ lxcmandir = join_paths(datadir, 'man') conf.set_quoted('BINDIR', bindir) conf.set_quoted('LIBDIR', libdir) conf.set_quoted('LOCALSTATEDIR', localstatedir) -conf.set_quoted('RUNTIME_PATH', runtimepath) +conf.set_quoted('DEFAULT_RUNTIME_PATH', runtimepath) conf.set_quoted('SYSCONFDIR', sysconfdir) conf.set_quoted('LXCCONFDIR', lxcconfdir) diff --git a/src/bindings.c b/src/bindings.c index dc0550ca..7f840af2 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -40,15 +41,32 @@ #include "syscall_numbers.h" #include "utils.h" +/* directory under which we mount the controllers - /run/lxcfs/controllers */ +#define BASEDIR "/lxcfs/controllers" +#define ROOTDIR "/lxcfs/root" + static bool can_use_pidfd; static bool can_use_swap; static bool can_use_sys_cpu; static bool has_versioned_opts; static bool memory_is_cgroupv2; static __u32 host_personality; +static char runtime_path[PATH_MAX] = DEFAULT_RUNTIME_PATH; + static volatile sig_atomic_t reload_successful; + +static char *get_base_dir(void) +{ + return must_make_path(runtime_path, BASEDIR, NULL); +} + +static char *get_root_dir(void) +{ + return must_make_path(runtime_path, ROOTDIR, NULL); +} + bool liblxcfs_functional(void) { return reload_successful != 0; @@ -580,8 +598,9 @@ pid_t lookup_initpid_in_store(pid_t pid) static bool umount_if_mounted(void) { - if (umount2(BASEDIR, MNT_DETACH) < 0 && errno != EINVAL) { - lxcfs_error("Failed to unmount %s: %s.\n", BASEDIR, strerror(errno)); + __do_free char *base_dir = get_base_dir(); + if (umount2(base_dir, MNT_DETACH) < 0 && errno != EINVAL) { + lxcfs_error("Failed to unmount %s: %s.\n", base_dir, strerror(errno)); return false; } return true; @@ -639,13 +658,14 @@ static bool is_on_ramfs(void) static int pivot_enter(void) { __do_close int oldroot = -EBADF, newroot = -EBADF; + __do_free char *root_dir = get_root_dir(); oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC); if (oldroot < 0) return log_error_errno(-1, errno, "Failed to open old root for fchdir"); - newroot = open(ROOTDIR, O_DIRECTORY | O_RDONLY | O_CLOEXEC); + newroot = open(root_dir, O_DIRECTORY | O_RDONLY | O_CLOEXEC); if (newroot < 0) return log_error_errno(-1, errno, "Failed to open new root for fchdir"); @@ -654,7 +674,7 @@ static int pivot_enter(void) if (fchdir(newroot) < 0) return log_error_errno(-1, errno, "Failed to change directory to new rootfs: %s", - ROOTDIR); + root_dir); /* pivot_root into our new root fs */ if (pivot_root(".", ".") < 0) @@ -681,8 +701,10 @@ static int pivot_enter(void) static int chroot_enter(void) { - if (mount(ROOTDIR, "/", NULL, MS_REC | MS_BIND, NULL)) { - lxcfs_error("Failed to recursively bind-mount %s into /.", ROOTDIR); + __do_free char *root_dir = get_root_dir(); + + if (mount(root_dir, "/", NULL, MS_REC | MS_BIND, NULL)) { + lxcfs_error("Failed to recursively bind-mount %s into /.", root_dir); return -1; } @@ -725,23 +747,33 @@ static int permute_and_enter(void) /* Prepare our new clean root. */ static int permute_prepare(void) { - if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) { + __do_free char *base_dir = get_base_dir(); + __do_free char *root_dir = get_root_dir(); + __do_free char *new_runtime = must_make_path(root_dir, runtime_path, NULL); + __do_free char *new_base_dir = must_make_path(root_dir, base_dir, NULL); + + if (mkdir(root_dir, 0700) < 0 && errno != EEXIST) { lxcfs_error("%s\n", "Failed to create directory for new root."); return -1; } - if (mount("/", ROOTDIR, NULL, MS_BIND, 0) < 0) { + if (mount("/", root_dir, NULL, MS_BIND, 0) < 0) { lxcfs_error("Failed to bind-mount / for new root: %s.\n", strerror(errno)); return -1; } - if (mount(RUNTIME_PATH, ROOTDIR RUNTIME_PATH, NULL, MS_BIND, 0) < 0) { - lxcfs_error("Failed to bind-mount /run into new root: %s.\n", strerror(errno)); + if (!mkdir_p(new_runtime, 0700)) { + lxcfs_error("Failed to create dir %s\n", new_runtime); + return -1; + } + + if (mount(runtime_path, new_runtime, NULL, MS_BIND, 0) < 0) { + lxcfs_error("Failed to bind-mount %s into new root: %s.\n", runtime_path, strerror(errno)); return -1; } - if (mount(BASEDIR, ROOTDIR BASEDIR, NULL, MS_REC | MS_MOVE, 0) < 0) { - printf("Failed to move " BASEDIR " into new root: %s.\n", strerror(errno)); + if (mount(base_dir, new_base_dir, NULL, MS_REC | MS_MOVE, 0) < 0) { + printf("Failed to move %s into new root: %s.\n", base_dir, strerror(errno)); return -1; } @@ -764,7 +796,9 @@ static bool permute_root(void) static bool cgfs_prepare_mounts(void) { - if (!mkdir_p(BASEDIR, 0700)) { + __do_free char *base_dir = get_base_dir(); + + if (!mkdir_p(base_dir, 0700)) { lxcfs_error("%s\n", "Failed to create lxcfs cgroup mountpoint."); return false; } @@ -790,7 +824,7 @@ static bool cgfs_prepare_mounts(void) return false; } - if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) { + if (mount("tmpfs", base_dir, "tmpfs", 0, "size=100000,mode=700") < 0) { lxcfs_error("%s\n", "Failed to mount tmpfs over lxcfs cgroup mountpoint."); return false; } @@ -800,14 +834,17 @@ static bool cgfs_prepare_mounts(void) static bool cgfs_mount_hierarchies(void) { - if (!mkdir_p(BASEDIR DEFAULT_CGROUP_MOUNTPOINT, 0755)) + __do_free char *base_dir = get_base_dir(); + __do_free char *base_dir_cgroup_mount = must_make_path(base_dir, DEFAULT_CGROUP_MOUNTPOINT, NULL); + + if (!mkdir_p(base_dir_cgroup_mount, 0700)) return false; - if (!cgroup_ops->mount(cgroup_ops, BASEDIR)) + if (!cgroup_ops->mount(cgroup_ops, base_dir)) return false; for (struct hierarchy **h = cgroup_ops->hierarchies; h && *h; h++) { - __do_free char *path = must_make_path(BASEDIR, (*h)->mountpoint, NULL); + __do_free char *path = must_make_path(base_dir, (*h)->mountpoint, NULL); (*h)->fd = open(path, O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); if ((*h)->fd < 0) return false; @@ -862,7 +899,19 @@ static void sigusr2_toggle_virtualization(int signo, siginfo_t *info, void *extr return; } -static void __attribute__((constructor)) lxcfs_init(void) +bool set_runtime_path(const char* new_path) +{ + if (new_path && strlen(new_path) < PATH_MAX) { + strcpy(runtime_path, new_path); + lxcfs_info("Using runtime path %s", runtime_path); + return true; + } else { + lxcfs_error("%s\n", "Failed to overwrite the runtime path"); + return false; + } +} + +void lxcfslib_init(void) { __do_close int init_ns = -EBADF, root_fd = -EBADF, pidfd = -EBADF; @@ -871,7 +920,7 @@ static void __attribute__((constructor)) lxcfs_init(void) pid_t pid; struct hierarchy *hierarchy; - lxcfs_info("Running constructor %s to reload liblxcfs", __func__); + lxcfs_info("Running %s to reload liblxcfs", __func__); cgroup_ops = cgroup_init(); if (!cgroup_ops) { @@ -971,9 +1020,20 @@ static void __attribute__((destructor)) lxcfs_exit(void) void *lxcfs_fuse_init(struct fuse_conn_info *conn, void *data) { struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = fc ? fc->private_data : NULL; + #if HAVE_FUSE_RETURNS_DT_TYPE can_use_sys_cpu = true; #endif has_versioned_opts = true; - return fc ? fc->private_data : NULL; + + // We can read runtime_path as of opts version 2. + if (opts && opts->version >= 2) { + set_runtime_path(opts->runtime_path); + } + + /* initialize the library */ + lxcfslib_init(); + + return opts; } diff --git a/src/bindings.h b/src/bindings.h index 617179df..7808a236 100644 --- a/src/bindings.h +++ b/src/bindings.h @@ -23,10 +23,6 @@ #include "proc_loadavg.h" #include "sysfs_fuse.h" -/* directory under which we mount the controllers - /run/lxcfs/controllers */ -#define BASEDIR RUNTIME_PATH "/lxcfs/controllers" -#define ROOTDIR RUNTIME_PATH "/lxcfs/root" - /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */ #define LXCFS_NUMSTRLEN64 21 @@ -116,6 +112,8 @@ struct lxcfs_opts { * and the use of bool instead of explicited __u32 and __u64 we can't. */ __u32 version; + // As of opts version 2. + char runtime_path[PATH_MAX]; }; typedef enum lxcfs_opt_t { diff --git a/src/lxcfs.c b/src/lxcfs.c index 9fb19cfd..2f16257e 100644 --- a/src/lxcfs.c +++ b/src/lxcfs.c @@ -32,7 +32,11 @@ #include "macro.h" #include "memory_utils.h" +#define PID_FILE "/lxcfs.pid" + void *dlopen_handle; +static char runtime_path[PATH_MAX] = DEFAULT_RUNTIME_PATH; + /* Functions to keep track of number of threads using the library */ @@ -146,7 +150,7 @@ static int stop_loadavg(void) static volatile sig_atomic_t need_reload; -static int lxcfs_init_library(void) +static int do_lxcfs_fuse_init(void) { char *error; void *(*__lxcfs_fuse_init)(struct fuse_conn_info * conn, void * cfg); @@ -199,13 +203,12 @@ static void do_reload(bool reinit) dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY); if (!dlopen_handle) - log_exit("%s - Failed to open liblxcfs.so", dlerror()); + log_exit("%s - Failed to open liblxcfs.so at %s", dlerror(), lxcfs_lib_path); else lxcfs_debug("Opened %s", lxcfs_lib_path); good: - /* initialize the library */ - if (reinit && lxcfs_init_library() < 0) { + if (reinit && do_lxcfs_fuse_init() < 0) { log_exit("Failed to initialize liblxcfs.so"); } @@ -1119,7 +1122,7 @@ static void *lxcfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg) static void *lxcfs_init(struct fuse_conn_info *conn) #endif { - if (lxcfs_init_library() < 0) + if (do_lxcfs_fuse_init() < 0) return NULL; #if HAVE_FUSE3 @@ -1187,12 +1190,14 @@ static void usage(void) 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(" Default pidfile is %s/lxcfs.pid", DEFAULT_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"); lxcfs_info(" --enable-cgroup Enable cgroup emulation code"); + lxcfs_info(" --runtime-dir=DIR Path to use as the runtime directory."); + lxcfs_info(" Default is %s", DEFAULT_RUNTIME_PATH); exit(EXIT_FAILURE); } @@ -1244,6 +1249,7 @@ static const struct option long_options[] = { {"enable-cgroup", no_argument, 0, 0 }, {"pidfile", required_argument, 0, 'p' }, + {"runtime-dir", required_argument, 0, 0 }, { }, }; @@ -1286,7 +1292,7 @@ int main(int argc, char *argv[]) int pidfile_fd = -EBADF; int ret = EXIT_FAILURE; char *pidfile = NULL, *token = NULL; - char pidfile_buf[STRLITERALLEN(RUNTIME_PATH) + STRLITERALLEN("/lxcfs.pid") + 1] = {}; + char pidfile_buf[PATH_MAX + sizeof(PID_FILE)] = {}; bool debug = false, foreground = false; #if !HAVE_FUSE3 bool nonempty = false; @@ -1303,6 +1309,7 @@ int main(int argc, char *argv[]) char *new_fuse_opts = NULL; char *const *new_argv; struct lxcfs_opts *opts; + char *runtime_path_arg = NULL; opts = malloc(sizeof(struct lxcfs_opts)); if (opts == NULL) { @@ -1313,7 +1320,7 @@ int main(int argc, char *argv[]) opts->swap_off = false; opts->use_pidfd = false; opts->use_cfs = false; - opts->version = 1; + opts->version = 2; while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) { switch (c) { @@ -1324,6 +1331,8 @@ int main(int argc, char *argv[]) opts->use_cfs = true; else if (strcmp(long_options[idx].name, "enable-cgroup") == 0) cgroup_is_enabled = true; + else if (strcmp(long_options[idx].name, "runtime-dir") == 0) + runtime_path_arg = optarg; else usage(); break; @@ -1376,6 +1385,12 @@ int main(int argc, char *argv[]) goto out; } + if (runtime_path_arg) { + strcpy(runtime_path, runtime_path_arg); + lxcfs_info("runtime path set to %s", runtime_path); + } + strcpy(opts->runtime_path, runtime_path); + fuse_argv[fuse_argc++] = argv[0]; if (debug) fuse_argv[fuse_argc++] = "-d"; @@ -1467,6 +1482,7 @@ int main(int argc, char *argv[]) lxcfs_info("Starting LXCFS at %s", argv[0]); do_reload(false); + if (install_signal_handler(SIGUSR1, sigusr1_reload)) { lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno)); goto out; @@ -1480,7 +1496,7 @@ int main(int argc, char *argv[]) #endif if (!pidfile) { - snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH); + snprintf(pidfile_buf, sizeof(pidfile_buf), "%s%s", runtime_path, PID_FILE); pidfile = pidfile_buf; } diff --git a/tests/main.sh.in b/tests/main.sh.in index 42540e33..088286d6 100755 --- a/tests/main.sh.in +++ b/tests/main.sh.in @@ -49,7 +49,7 @@ if [ -x ${lxcfs} ]; then LXCFSPID=$! else UNSHARE=0 - LXCFSPID=$(cat "{{RUNTIME_PATH}}/lxcfs.pid") + LXCFSPID=$(cat "{{DEFAULT_RUNTIME_PATH}}/lxcfs.pid") echo "=> Re-using host lxcfs" rmdir $LXCFSDIR export LXCFSDIR=/var/lib/lxcfs