Commit 81c75799 by Daniel Lezcano

lxc: enter / exec a command inside a container V2

This patch allows to execute a command or enter inside the container: * lxc-attach -n <name> [command] If the <command is not specified>, the lxc-attach will retrieve your uid and get your shell name and exec it in the container. Signed-off-by: 's avatarDaniel Lezcano <dlezcano@fr.ibm.com>
parent 28a4b0e5
...@@ -67,6 +67,7 @@ bin_SCRIPTS = \ ...@@ -67,6 +67,7 @@ bin_SCRIPTS = \
lxc-destroy lxc-destroy
bin_PROGRAMS = \ bin_PROGRAMS = \
lxc-attach \
lxc-unshare \ lxc-unshare \
lxc-stop \ lxc-stop \
lxc-start \ lxc-start \
...@@ -87,6 +88,7 @@ libexec_PROGRAMS = \ ...@@ -87,6 +88,7 @@ libexec_PROGRAMS = \
AM_LDFLAGS=-Wl,-E -Wl,-rpath -Wl,$(libdir) AM_LDFLAGS=-Wl,-E -Wl,-rpath -Wl,$(libdir)
LDADD=liblxc.so LDADD=liblxc.so
lxc_attach_SOURCES = lxc_attach.c
lxc_cgroup_SOURCES = lxc_cgroup.c lxc_cgroup_SOURCES = lxc_cgroup.c
lxc_checkpoint_SOURCES = lxc_checkpoint.c lxc_checkpoint_SOURCES = lxc_checkpoint.c
lxc_console_SOURCES = lxc_console.c lxc_console_SOURCES = lxc_console.c
......
...@@ -114,6 +114,7 @@ extern void lxc_console_remove_fd(int, struct lxc_tty_info *); ...@@ -114,6 +114,7 @@ extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *); 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_stop_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_state_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, static int trigger_command(int fd, struct lxc_request *request,
struct lxc_handler *handler) struct lxc_handler *handler)
...@@ -124,6 +125,7 @@ static int trigger_command(int fd, struct lxc_request *request, ...@@ -124,6 +125,7 @@ static int trigger_command(int fd, struct lxc_request *request,
[LXC_COMMAND_TTY] = lxc_console_callback, [LXC_COMMAND_TTY] = lxc_console_callback,
[LXC_COMMAND_STOP] = lxc_stop_callback, [LXC_COMMAND_STOP] = lxc_stop_callback,
[LXC_COMMAND_STATE] = lxc_state_callback, [LXC_COMMAND_STATE] = lxc_state_callback,
[LXC_COMMAND_PID] = lxc_pid_callback,
}; };
if (request->type < 0 || request->type >= LXC_COMMAND_MAX) if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
......
...@@ -27,6 +27,7 @@ enum { ...@@ -27,6 +27,7 @@ enum {
LXC_COMMAND_TTY, LXC_COMMAND_TTY,
LXC_COMMAND_STOP, LXC_COMMAND_STOP,
LXC_COMMAND_STATE, LXC_COMMAND_STATE,
LXC_COMMAND_PID,
LXC_COMMAND_MAX, LXC_COMMAND_MAX,
}; };
...@@ -38,6 +39,7 @@ struct lxc_request { ...@@ -38,6 +39,7 @@ struct lxc_request {
struct lxc_answer { struct lxc_answer {
int fd; int fd;
int ret; /* 0 on success, -errno on failure */ int ret; /* 0 on success, -errno on failure */
pid_t pid;
}; };
struct lxc_command { struct lxc_command {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
# When the capabilities are set, a non root user can manage the containers. # 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_CREATE_CAPS="cap_sys_admin"
LXC_NETSTAT_CAPS="cap_sys_admin" LXC_NETSTAT_CAPS="cap_sys_admin"
LXC_INIT_CAPS="cap_sys_admin,cap_dac_override" LXC_INIT_CAPS="cap_sys_admin,cap_dac_override"
...@@ -34,7 +35,6 @@ LXC_START_CAPS="$LXC_COMMON_CAPS,cap_fowner,cap_sys_chroot,cap_setpcap" ...@@ -34,7 +35,6 @@ LXC_START_CAPS="$LXC_COMMON_CAPS,cap_fowner,cap_sys_chroot,cap_setpcap"
LXC_EXECUTE_CAPS=$LXC_START_CAPS LXC_EXECUTE_CAPS=$LXC_START_CAPS
LXC_RESTART_CAPS="$LXC_START_CAPS,cap_mknod" LXC_RESTART_CAPS="$LXC_START_CAPS,cap_mknod"
LXC_CHECKPOINT_CAPS="$LXC_COMMON_CAPS,cap_sys_ptrace,cap_mknod" LXC_CHECKPOINT_CAPS="$LXC_COMMON_CAPS,cap_sys_ptrace,cap_mknod"
LXC_DROP_CAPS="" LXC_DROP_CAPS=""
usage() usage()
...@@ -44,6 +44,7 @@ usage() ...@@ -44,6 +44,7 @@ usage()
lxc_setcaps() lxc_setcaps()
{ {
setcap $LXC_ATTACH_CAPS=ep @BINDIR@/lxc-attach
setcap $LXC_CREATE_CAPS=ep @BINDIR@/lxc-create setcap $LXC_CREATE_CAPS=ep @BINDIR@/lxc-create
setcap $LXC_EXECUTE_CAPS=ep @BINDIR@/lxc-execute setcap $LXC_EXECUTE_CAPS=ep @BINDIR@/lxc-execute
setcap $LXC_START_CAPS=ep @BINDIR@/lxc-start setcap $LXC_START_CAPS=ep @BINDIR@/lxc-start
......
/*
* 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;
}
...@@ -25,9 +25,28 @@ ...@@ -25,9 +25,28 @@
#include <alloca.h> #include <alloca.h>
#include <errno.h> #include <errno.h>
#include <signal.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); lxc_log_define(lxc_namespace, lxc);
...@@ -36,6 +55,16 @@ struct clone_arg { ...@@ -36,6 +55,16 @@ struct clone_arg {
void *arg; 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) static int do_clone(void *arg)
{ {
struct clone_arg *clone_arg = arg; struct clone_arg *clone_arg = arg;
...@@ -64,3 +93,32 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags) ...@@ -64,3 +93,32 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
return ret; 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;
}
...@@ -49,5 +49,6 @@ ...@@ -49,5 +49,6 @@
#endif #endif
extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags); extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
extern int lxc_attach(pid_t pid);
#endif #endif
...@@ -204,6 +204,28 @@ static int sigchld_handler(int fd, void *data, ...@@ -204,6 +204,28 @@ static int sigchld_handler(int fd, void *data,
return 1; 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) int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
{ {
handler->state = state; handler->state = state;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment