lxc-destroy
bin_PROGRAMS = \
+ lxc-attach \
lxc-unshare \
lxc-stop \
lxc-start \
AM_LDFLAGS=-Wl,-E -Wl,-rpath -Wl,$(libdir)
LDADD=liblxc.so
+lxc_attach_SOURCES = lxc_attach.c
lxc_cgroup_SOURCES = lxc_cgroup.c
lxc_checkpoint_SOURCES = lxc_checkpoint.c
lxc_console_SOURCES = lxc_console.c
extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
+extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
static int trigger_command(int fd, struct lxc_request *request,
struct lxc_handler *handler)
[LXC_COMMAND_TTY] = lxc_console_callback,
[LXC_COMMAND_STOP] = lxc_stop_callback,
[LXC_COMMAND_STATE] = lxc_state_callback,
+ [LXC_COMMAND_PID] = lxc_pid_callback,
};
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
LXC_COMMAND_TTY,
LXC_COMMAND_STOP,
LXC_COMMAND_STATE,
+ LXC_COMMAND_PID,
LXC_COMMAND_MAX,
};
struct lxc_answer {
int fd;
int ret; /* 0 on success, -errno on failure */
+ pid_t pid;
};
struct lxc_command {
# When the capabilities are set, a non root user can manage the containers.
#
+LXC_ATTACH_CAP="cap_sys_admin"
LXC_CREATE_CAPS="cap_sys_admin"
LXC_NETSTAT_CAPS="cap_sys_admin"
LXC_INIT_CAPS="cap_sys_admin,cap_dac_override"
LXC_EXECUTE_CAPS=$LXC_START_CAPS
LXC_RESTART_CAPS="$LXC_START_CAPS,cap_mknod"
LXC_CHECKPOINT_CAPS="$LXC_COMMON_CAPS,cap_sys_ptrace,cap_mknod"
-
LXC_DROP_CAPS=""
usage()
lxc_setcaps()
{
+ setcap $LXC_ATTACH_CAPS=ep @BINDIR@/lxc-attach
setcap $LXC_CREATE_CAPS=ep @BINDIR@/lxc-create
setcap $LXC_EXECUTE_CAPS=ep @BINDIR@/lxc-execute
setcap $LXC_START_CAPS=ep @BINDIR@/lxc-start
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2010
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include "commands.h"
+#include "arguments.h"
+#include "namespace.h"
+#include "log.h"
+
+lxc_log_define(lxc_attach_ui, lxc);
+
+static const struct option my_longopts[] = {
+ LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+ .progname = "lxc-attach",
+ .help = "\
+--name=NAME\n\
+\n\
+Execute the specified command - enter the container NAME\n\
+\n\
+Options :\n\
+ -n, --name=NAME NAME for name of the container\n",
+ .options = my_longopts,
+ .parser = NULL,
+ .checker = NULL,
+};
+
+pid_t get_init_pid(const char *name)
+{
+ struct lxc_command command = {
+ .request = { .type = LXC_COMMAND_PID },
+ };
+
+ int ret, stopped = 0;
+
+ ret = lxc_command(name, &command, &stopped);
+ if (ret < 0 && stopped) {
+ INFO("'%s' is already stopped", name);
+ return 0;
+ }
+
+ if (ret < 0) {
+ ERROR("failed to send command");
+ return -1;
+ }
+
+ if (command.answer.ret) {
+ ERROR("failed to retrieve the init pid: %s",
+ strerror(command.answer.ret));
+ return -1;
+ }
+
+ return command.answer.pid;
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+ int ret;
+ pid_t pid;
+ struct passwd *passwd;
+ uid_t uid;
+
+ ret = lxc_arguments_parse(&my_args, argc, argv);
+ if (ret)
+ return ret;
+
+ ret = lxc_log_init(my_args.log_file, my_args.log_priority,
+ my_args.progname, my_args.quiet);
+ if (ret)
+ return ret;
+
+ pid = get_init_pid(my_args.name);
+ if (pid < 0) {
+ ERROR("failed to get the init pid");
+ return -1;
+ }
+
+ ret = lxc_attach(pid);
+ if (ret < 0) {
+ ERROR("failed to enter the namespace");
+ return -1;
+ }
+
+ if (my_args.argc) {
+ execve(my_args.argv[0], my_args.argv, envp);
+ SYSERROR("failed to exec '%s'", my_args.argv[0]);
+ return -1;
+ }
+
+ uid = getuid();
+
+ passwd = getpwuid(uid);
+ if (!passwd) {
+ SYSERROR("failed to get passwd entry for uid '%d'", uid);
+ return -1;
+ }
+
+ {
+ char *const args[] = {
+ passwd->pw_shell,
+ NULL,
+ };
+
+ execve(args[0], args, envp);
+ SYSERROR("failed to exec '%s'", args[0]);
+ return -1;
+ }
+
+ return 0;
+}
#include <alloca.h>
#include <errno.h>
#include <signal.h>
-#include <namespace.h>
+#include <syscall.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
-#include <lxc/log.h>
+#include "namespace.h"
+#include "log.h"
+
+#ifndef __NR_setns
+# if __i386__
+# define __NR_setns 338
+# elif __x86_64__
+# define __NR_setns 300
+# elif __powerpc__
+# define __NR_setns 323
+# elif __s390__
+# define __NR_setns 332
+# else
+# warning "architecture not supported for setns"
+# endif
+#endif
lxc_log_define(lxc_namespace, lxc);
void *arg;
};
+int setns(int nstype, int fd)
+{
+#ifndef __NR_setns
+ errno = ENOSYS;
+ return -1;
+#else
+ return syscall(__NR_setns, nstype, fd);
+#endif
+}
+
static int do_clone(void *arg)
{
struct clone_arg *clone_arg = arg;
return ret;
}
+
+int lxc_attach(pid_t pid)
+{
+ char path[MAXPATHLEN];
+ char *ns[] = { "pid", "mnt", "net", "pid", "uts" };
+ const int size = sizeof(ns) / sizeof(char *);
+ int fd[size];
+ int i;
+
+ for (i = 0; i < size; i++) {
+ sprintf(path, "/proc/%d/ns/%s", pid, ns[i]);
+ fd[i] = open(path, O_RDONLY);
+ if (fd[i] < 0) {
+ SYSERROR("failed to open '%s'", path);
+ return -1;
+ }
+ }
+
+ for (i = 0; i < size; i++) {
+ if (setns(0, fd[i])) {
+ SYSERROR("failed to set namespace '%s'", ns[i]);
+ return -1;
+ }
+
+ close(fd[i]);
+ }
+
+ return 0;
+}
#endif
extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
+extern int lxc_attach(pid_t pid);
#endif
return 1;
}
+int lxc_pid_callback(int fd, struct lxc_request *request, struct lxc_handler *handler)
+{
+ struct lxc_answer answer;
+ int ret;
+
+ answer.pid = handler->pid;
+ answer.ret = 0;
+
+ ret = send(fd, &answer, sizeof(answer), 0);
+ if (ret < 0) {
+ WARN("failed to send answer to the peer");
+ return -1;
+ }
+
+ if (ret != sizeof(answer)) {
+ ERROR("partial answer sent");
+ return -1;
+ }
+
+ return 0;
+}
+
int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
{
handler->state = state;