{
fprintf(stderr, "%s <options> [command]\n", basename(cmd));
fprintf(stderr, "Options are:\n");
- fprintf(stderr, "\t -f : fork and unshare (automatic when unsharing the pids)\n");
fprintf(stderr, "\t -s flags: Ored list of flags to unshare:\n" \
"\t MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
fprintf(stderr, "\t -u <id> : new id to be set if -s USER is specified\n");
return -1;
}
-static int lxc_fill_namespace_flags(char *flaglist, long *flags)
+static int lxc_fill_namespace_flags(char *flaglist, int *flags)
{
char *token, *saveptr = NULL;
int aflag;
return 0;
}
+
+struct start_arg {
+ char ***args;
+ int *flags;
+ uid_t *uid;
+};
+
+static int do_start(void *arg)
+{
+ struct start_arg *start_arg = arg;
+ char **args = *start_arg->args;
+ int flags = *start_arg->flags;
+ uid_t uid = *start_arg->uid;
+
+ if (flags & CLONE_NEWUSER && setuid(uid)) {
+ ERROR("failed to set uid %d: %s", uid, strerror(errno));
+ exit(1);
+ }
+
+ execvp(args[0], args);
+
+ ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
+ return 1;
+}
+
int main(int argc, char *argv[])
{
- int opt, status = 1, hastofork = 0;
+ int opt, status;
int ret;
char *namespaces = NULL;
char **args;
- long flags = 0;
+ int flags = 0;
uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
pid_t pid;
- while ((opt = getopt(argc, argv, "fs:u:")) != -1) {
+ struct start_arg start_arg = {
+ .args = &args,
+ .uid = &uid,
+ .flags = &flags,
+ };
+
+ while ((opt = getopt(argc, argv, "s:u:")) != -1) {
switch (opt) {
case 's':
namespaces = optarg;
uid = lookup_user(optarg);
if (uid == -1)
return 1;
- case 'f':
- hastofork = 1;
- break;
}
}
args = &argv[optind];
ret = lxc_fill_namespace_flags(namespaces, &flags);
- if (ret)
+ if (ret)
usage(argv[0]);
if (!(flags & CLONE_NEWUSER) && uid != -1) {
- ERROR("-u <uid> need -s USER option");
- return 1;
- }
-
- if ((flags & CLONE_NEWPID) || hastofork) {
-
- if (!argv[optind] || !strlen(argv[optind]))
- usage(argv[0]);
-
- pid = fork_ns(flags);
-
- if (pid < 0) {
- ERROR("failed to fork into a new namespace: %s",
- strerror(errno));
- return 1;
- }
-
- if (!pid) {
- if (flags & CLONE_NEWUSER && setuid(uid)) {
- ERROR("failed to set uid %d: %s",
- uid, strerror(errno));
- exit(1);
- }
-
- execvp(args[0], args);
- ERROR("failed to exec: '%s': %s",
- argv[0], strerror(errno));
- exit(1);
- }
-
- if (waitpid(pid, &status, 0) < 0)
- ERROR("failed to wait for '%d'", pid);
-
- return status;
- }
-
- if (unshare_ns(flags)) {
- ERROR("failed to unshare the current process: %s",
- strerror(errno));
+ ERROR("-u <uid> needs -s USER option");
return 1;
}
- if (flags & CLONE_NEWUSER && setuid(uid)) {
- ERROR("failed to set uid %d: %s",
- uid, strerror(errno));
- return 1;
+ pid = lxc_clone(do_start, &start_arg, flags);
+ if (pid < 0) {
+ ERROR("failed to clone");
+ return -1;
}
- if (argv[optind] && strlen(argv[optind])) {
- execvp(args[0], args);
- ERROR("failed to exec: '%s': %s",
- argv[0], strerror(errno));
- return 1;
+ if (waitpid(pid, &status, 0) < 0) {
+ ERROR("failed to wait for '%d'", pid);
+ return -1;
}
- return 0;
+ return status;
}
#include <signal.h>
#include <fcntl.h>
#include <termios.h>
+#include <namespace.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/mount.h>
kill(handler->pid, SIGKILL);
}
+struct start_arg {
+ const char *name;
+ char *const *argv;
+ struct lxc_handler *handler;
+ int *sv;
+};
+
+static int do_start(void *arg)
+{
+ struct start_arg *start_arg = arg;
+ struct lxc_handler *handler = start_arg->handler;
+ const char *name = start_arg->name;
+ char *const *argv = start_arg->argv;
+ int *sv = start_arg->sv;
+ int err = -1, sync;
+
+ if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
+ SYSERROR("failed to set sigprocmask");
+ goto out_child;
+ }
+
+ close(sv[1]);
+
+ /* Be sure we don't inherit this after the exec */
+ fcntl(sv[0], F_SETFD, FD_CLOEXEC);
+
+ /* Tell our father he can begin to configure the container */
+ if (write(sv[0], &sync, sizeof(sync)) < 0) {
+ SYSERROR("failed to write socket");
+ goto out_child;
+ }
+
+ /* Wait for the father to finish the configuration */
+ if (read(sv[0], &sync, sizeof(sync)) < 0) {
+ SYSERROR("failed to read socket");
+ goto out_child;
+ }
+
+ /* Setup the container, ip, names, utsname, ... */
+ if (lxc_setup(name, handler->tty, &handler->tty_info)) {
+ ERROR("failed to setup the container");
+ goto out_warn_father;
+ }
+
+ if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
+ SYSERROR("failed to remove CAP_SYS_BOOT capability");
+ goto out_child;
+ }
+
+ execvp(argv[0], argv);
+ SYSERROR("failed to exec %s", argv[0]);
+
+out_warn_father:
+ /* If the exec fails, tell that to our father */
+ if (write(sv[0], &err, sizeof(err)) < 0)
+ SYSERROR("failed to write the socket");
+out_child:
+ return -1;
+}
+
int lxc_spawn(const char *name, struct lxc_handler *handler, char *const argv[])
{
int sv[2];
int clone_flags;
int err = -1, sync;
+ struct start_arg start_arg = {
+ .name = name,
+ .argv = argv,
+ .handler = handler,
+ .sv = sv,
+ };
+
/* Synchro socketpair */
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
SYSERROR("failed to create communication socketpair");
clone_flags |= CLONE_NEWNET;
/* Create a process in a new set of namespaces */
- handler->pid = fork_ns(clone_flags);
+ handler->pid = lxc_clone(do_start, &start_arg, clone_flags);
if (handler->pid < 0) {
SYSERROR("failed to fork into a new namespace");
goto out_close;
}
- if (!handler->pid) {
-
- if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
- SYSERROR("failed to set sigprocmask");
- goto out_child;
- }
-
- close(sv[1]);
-
- /* Be sure we don't inherit this after the exec */
- fcntl(sv[0], F_SETFD, FD_CLOEXEC);
-
- /* Tell our father he can begin to configure the container */
- if (write(sv[0], &sync, sizeof(sync)) < 0) {
- SYSERROR("failed to write socket");
- goto out_child;
- }
-
- /* Wait for the father to finish the configuration */
- if (read(sv[0], &sync, sizeof(sync)) < 0) {
- SYSERROR("failed to read socket");
- goto out_child;
- }
-
- /* Setup the container, ip, names, utsname, ... */
- if (lxc_setup(name, handler->tty, &handler->tty_info)) {
- ERROR("failed to setup the container");
- goto out_warn_father;
- }
-
- if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
- SYSERROR("failed to remove CAP_SYS_BOOT capability");
- goto out_child;
- }
-
- execvp(argv[0], argv);
- SYSERROR("failed to exec %s", argv[0]);
-
- out_warn_father:
- /* If the exec fails, tell that to our father */
- if (write(sv[0], &err, sizeof(err)) < 0)
- SYSERROR("failed to write the socket");
- out_child:
- exit(err);
- }
-
close(sv[0]);
/* Wait for the child to be ready */