Commit cee1de17 by Serge Hallyn

Merge pull request #825 from brauner/2016-02-15/lxc_attach_pty

make lxc-attach use a pty
parents 0b095804 5eacdc3d
...@@ -1332,7 +1332,7 @@ out: ...@@ -1332,7 +1332,7 @@ out:
return bret; return bret;
} }
static bool collect_subsytems(void) static bool collect_subsystems(void)
{ {
char *line = NULL; char *line = NULL;
nih_local char **cgm_subsys_list = NULL; nih_local char **cgm_subsys_list = NULL;
...@@ -1444,7 +1444,7 @@ out_free: ...@@ -1444,7 +1444,7 @@ out_free:
struct cgroup_ops *cgm_ops_init(void) struct cgroup_ops *cgm_ops_init(void)
{ {
check_supports_multiple_controllers(-1); check_supports_multiple_controllers(-1);
if (!collect_subsytems()) if (!collect_subsystems())
return NULL; return NULL;
if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS) if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS)
......
...@@ -22,26 +22,28 @@ ...@@ -22,26 +22,28 @@
*/ */
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <termios.h> #include <termios.h>
#include <unistd.h>
#include <lxc/lxccontainer.h> #include <lxc/lxccontainer.h>
#include "log.h" #include "af_unix.h"
#include "conf.h"
#include "config.h"
#include "start.h" /* for struct lxc_handler */
#include "caps.h" #include "caps.h"
#include "commands.h" #include "commands.h"
#include "mainloop.h" #include "conf.h"
#include "af_unix.h" #include "config.h"
#include "console.h"
#include "log.h"
#include "lxclock.h" #include "lxclock.h"
#include "mainloop.h"
#include "start.h" /* for struct lxc_handler */
#include "utils.h" #include "utils.h"
#if HAVE_PTY_H #if HAVE_PTY_H
...@@ -55,19 +57,6 @@ lxc_log_define(lxc_console, lxc); ...@@ -55,19 +57,6 @@ lxc_log_define(lxc_console, lxc);
static struct lxc_list lxc_ttys; static struct lxc_list lxc_ttys;
typedef void (*sighandler_t)(int); typedef void (*sighandler_t)(int);
struct lxc_tty_state
{
struct lxc_list node;
int stdinfd;
int stdoutfd;
int masterfd;
int escape;
int saw_escape;
const char *winch_proxy;
const char *winch_proxy_lxcpath;
int sigfd;
sigset_t oldmask;
};
__attribute__((constructor)) __attribute__((constructor))
void lxc_console_init(void) void lxc_console_init(void)
...@@ -80,7 +69,7 @@ void lxc_console_init(void) ...@@ -80,7 +69,7 @@ void lxc_console_init(void)
* @srcfd : terminal to get size from (typically a slave pty) * @srcfd : terminal to get size from (typically a slave pty)
* @dstfd : terminal to set size on (typically a master pty) * @dstfd : terminal to set size on (typically a master pty)
*/ */
static void lxc_console_winsz(int srcfd, int dstfd) void lxc_console_winsz(int srcfd, int dstfd)
{ {
struct winsize wsz; struct winsize wsz;
if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) { if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
...@@ -93,10 +82,8 @@ static void lxc_console_winsz(int srcfd, int dstfd) ...@@ -93,10 +82,8 @@ static void lxc_console_winsz(int srcfd, int dstfd)
static void lxc_console_winch(struct lxc_tty_state *ts) static void lxc_console_winch(struct lxc_tty_state *ts)
{ {
lxc_console_winsz(ts->stdinfd, ts->masterfd); lxc_console_winsz(ts->stdinfd, ts->masterfd);
if (ts->winch_proxy) { if (ts->winch_proxy)
lxc_cmd_console_winch(ts->winch_proxy, lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
ts->winch_proxy_lxcpath);
}
} }
void lxc_console_sigwinch(int sig) void lxc_console_sigwinch(int sig)
...@@ -110,13 +97,14 @@ void lxc_console_sigwinch(int sig) ...@@ -110,13 +97,14 @@ void lxc_console_sigwinch(int sig)
} }
} }
static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata, int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
struct signalfd_siginfo siginfo; struct signalfd_siginfo siginfo;
struct lxc_tty_state *ts = cbdata; struct lxc_tty_state *ts = cbdata;
if (read(fd, &siginfo, sizeof(siginfo)) < sizeof(siginfo)) { ssize_t ret = read(fd, &siginfo, sizeof(siginfo));
if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
ERROR("failed to read signal info"); ERROR("failed to read signal info");
return -1; return -1;
} }
...@@ -145,7 +133,7 @@ static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata, ...@@ -145,7 +133,7 @@ static int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
* prevent lxc_ttys list corruption, but using the fd we can provide the * prevent lxc_ttys list corruption, but using the fd we can provide the
* tty_state needed to the callback (lxc_console_cb_sigwinch_fd()). * tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
*/ */
static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd) struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
{ {
sigset_t mask; sigset_t mask;
struct lxc_tty_state *ts; struct lxc_tty_state *ts;
...@@ -200,11 +188,11 @@ out: ...@@ -200,11 +188,11 @@ out:
* Must be called with process_lock held to protect the lxc_ttys list, or * Must be called with process_lock held to protect the lxc_ttys list, or
* from a non-threaded context. * from a non-threaded context.
*/ */
static void lxc_console_sigwinch_fini(struct lxc_tty_state *ts) void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
{ {
if (ts->sigfd >= 0) { if (ts->sigfd >= 0)
close(ts->sigfd); close(ts->sigfd);
}
lxc_list_del(&ts->node); lxc_list_del(&ts->node);
sigprocmask(SIG_SETMASK, &ts->oldmask, NULL); sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
free(ts); free(ts);
...@@ -243,6 +231,7 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data, ...@@ -243,6 +231,7 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
if (w != r) if (w != r)
WARN("console short write r:%d w:%d", r, w); WARN("console short write r:%d w:%d", r, w);
return 0; return 0;
} }
...@@ -302,7 +291,7 @@ int lxc_console_mainloop_add(struct lxc_epoll_descr *descr, ...@@ -302,7 +291,7 @@ int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
return 0; return 0;
} }
static int setup_tios(int fd, struct termios *oldtios) int lxc_setup_tios(int fd, struct termios *oldtios)
{ {
struct termios newtios; struct termios newtios;
...@@ -382,7 +371,7 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd) ...@@ -382,7 +371,7 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
return -1; return -1;
} }
if (setup_tios(console->peerpty.slave, &oldtermio) < 0) if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
goto err1; goto err1;
ts = lxc_console_sigwinch_init(console->peerpty.master, console->master); ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
...@@ -435,9 +424,8 @@ int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq) ...@@ -435,9 +424,8 @@ int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
} }
/* search for next available tty, fixup index tty1 => [0] */ /* search for next available tty, fixup index tty1 => [0] */
for (ttynum = 1; for (ttynum = 1; ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ttynum++)
ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ;
ttynum++);
/* we didn't find any available slot for tty */ /* we didn't find any available slot for tty */
if (ttynum > tty_info->nbtty) if (ttynum > tty_info->nbtty)
...@@ -521,7 +509,7 @@ static void lxc_console_peer_default(struct lxc_console *console) ...@@ -521,7 +509,7 @@ static void lxc_console_peer_default(struct lxc_console *console)
goto err1; goto err1;
} }
if (setup_tios(console->peer, console->tios) < 0) if (lxc_setup_tios(console->peer, console->tios) < 0)
goto err2; goto err2;
return; return;
...@@ -611,46 +599,60 @@ err: ...@@ -611,46 +599,60 @@ err:
return -1; return -1;
} }
int lxc_console_set_stdfds(struct lxc_handler *handler) int lxc_console_set_stdfds(int fd)
{ {
struct lxc_conf *conf = handler->conf; if (fd < 0)
struct lxc_console *console = &conf->console;
if (console->slave < 0)
return 0; return 0;
if (dup2(console->slave, 0) < 0 || if (isatty(STDIN_FILENO))
dup2(console->slave, 1) < 0 || if (dup2(fd, STDIN_FILENO) < 0) {
dup2(console->slave, 2) < 0) SYSERROR("failed to duplicate stdin.");
{ return -1;
SYSERROR("failed to dup console"); }
return -1;
} if (isatty(STDOUT_FILENO))
if (dup2(fd, STDOUT_FILENO) < 0) {
SYSERROR("failed to duplicate stdout.");
return -1;
}
if (isatty(STDERR_FILENO))
if (dup2(fd, STDERR_FILENO) < 0) {
SYSERROR("failed to duplicate stderr.");
return -1;
}
return 0; return 0;
} }
static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata, int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
struct lxc_tty_state *ts = cbdata; struct lxc_tty_state *ts = cbdata;
char c; char c;
if (events & EPOLLHUP)
return 1;
assert(fd == ts->stdinfd); assert(fd == ts->stdinfd);
if (read(ts->stdinfd, &c, 1) < 0) { if (read(ts->stdinfd, &c, 1) < 0) {
SYSERROR("failed to read"); SYSERROR("failed to read");
return 1; return 1;
} }
/* we want to exit the console with Ctrl+a q */ if (ts->escape != -1) {
if (c == ts->escape && !ts->saw_escape) { /* we want to exit the console with Ctrl+a q */
ts->saw_escape = 1; if (c == ts->escape && !ts->saw_escape) {
return 0; ts->saw_escape = 1;
} return 0;
}
if (c == 'q' && ts->saw_escape) if (c == 'q' && ts->saw_escape)
return 1; return 1;
ts->saw_escape = 0;
}
ts->saw_escape = 0;
if (write(ts->masterfd, &c, 1) < 0) { if (write(ts->masterfd, &c, 1) < 0) {
SYSERROR("failed to write"); SYSERROR("failed to write");
return 1; return 1;
...@@ -659,12 +661,15 @@ static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata, ...@@ -659,12 +661,15 @@ static int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
return 0; return 0;
} }
static int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata, int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
struct lxc_tty_state *ts = cbdata; struct lxc_tty_state *ts = cbdata;
char buf[1024]; char buf[1024];
int r,w; int r, w;
if (events & EPOLLHUP)
return 1;
assert(fd == ts->masterfd); assert(fd == ts->masterfd);
r = read(fd, buf, sizeof(buf)); r = read(fd, buf, sizeof(buf));
...@@ -701,7 +706,7 @@ int lxc_console(struct lxc_container *c, int ttynum, ...@@ -701,7 +706,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
return -1; return -1;
} }
ret = setup_tios(stdinfd, &oldtios); ret = lxc_setup_tios(stdinfd, &oldtios);
if (ret) { if (ret) {
ERROR("failed to setup tios"); ERROR("failed to setup tios");
return -1; return -1;
...@@ -782,3 +787,4 @@ err1: ...@@ -782,3 +787,4 @@ err1:
return ret; return ret;
} }
...@@ -24,8 +24,24 @@ ...@@ -24,8 +24,24 @@
#ifndef __LXC_CONSOLE_H #ifndef __LXC_CONSOLE_H
#define __LXC_CONSOLE_H #define __LXC_CONSOLE_H
#include "conf.h"
#include "list.h"
struct lxc_epoll_descr; struct lxc_epoll_descr;
struct lxc_container; struct lxc_container;
struct lxc_tty_state
{
struct lxc_list node;
int stdinfd;
int stdoutfd;
int masterfd;
int escape;
int saw_escape;
const char *winch_proxy;
const char *winch_proxy_lxcpath;
int sigfd;
sigset_t oldmask;
};
extern int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum); extern int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum);
extern int lxc_console_create(struct lxc_conf *); extern int lxc_console_create(struct lxc_conf *);
...@@ -39,6 +55,16 @@ extern int lxc_console(struct lxc_container *c, int ttynum, ...@@ -39,6 +55,16 @@ extern int lxc_console(struct lxc_container *c, int ttynum,
int escape); int escape);
extern int lxc_console_getfd(struct lxc_container *c, int *ttynum, extern int lxc_console_getfd(struct lxc_container *c, int *ttynum,
int *masterfd); int *masterfd);
extern int lxc_console_set_stdfds(struct lxc_handler *); extern int lxc_console_set_stdfds(int fd);
extern int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr);
extern int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr);
extern int lxc_setup_tios(int fd, struct termios *oldtios);
extern void lxc_console_winsz(int srcfd, int dstfd);
extern int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr);
extern struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd);
extern void lxc_console_sigwinch_fini(struct lxc_tty_state *ts);
#endif #endif
...@@ -23,19 +23,35 @@ ...@@ -23,19 +23,35 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include <assert.h> #include <assert.h>
#include <sys/wait.h> #include <errno.h>
#include <sys/types.h> #include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <lxc/lxccontainer.h>
#include "attach.h" #include "attach.h"
#include "arguments.h" #include "arguments.h"
#include "caps.h"
#include "config.h" #include "config.h"
#include "confile.h" #include "confile.h"
#include "namespace.h" #include "console.h"
#include "caps.h"
#include "log.h" #include "log.h"
#include "list.h"
#include "mainloop.h"
#include "utils.h" #include "utils.h"
#if HAVE_PTY_H
#include <pty.h>
#else
#include <../include/openpty.h>
#endif
lxc_log_define(lxc_attach_ui, lxc); lxc_log_define(lxc_attach_ui, lxc);
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
...@@ -186,20 +202,255 @@ Options :\n\ ...@@ -186,20 +202,255 @@ Options :\n\
.checker = NULL, .checker = NULL,
}; };
int main(int argc, char *argv[]) struct wrapargs {
lxc_attach_options_t *options;
lxc_attach_command_t *command;
struct lxc_tty_state *ts;
struct lxc_console *console;
int ptyfd;
};
/* Minimalistic forkpty() implementation. */
static pid_t fork_pty(int *masterfd)
{
int master, slave;
int ret = openpty(&master, &slave, NULL, NULL, NULL);
if (ret < 0)
return -1;
pid_t pid = fork();
if (pid < 0) {
close(master);
close(slave);
return -1;
} else if (pid == 0) {
close(master);
setsid();
if (ioctl(slave, TIOCSCTTY, NULL) < 0)
_Exit(-1); /* automatically closes fds */
if (lxc_console_set_stdfds(slave) < 0)
_Exit(-1); /* automatically closes fds */
return 0;
} else {
*masterfd = master;
close(slave);
return pid;
}
}
static int pty_in_container(void *p)
{ {
int ret; int ret;
int pid = -1;
int master = -1;
struct wrapargs *args = p;
INFO("Trying to allocate a pty in the container.");
if (!isatty(args->ptyfd)) {
ERROR("stdin is not a tty");
return -1;
}
/* Get termios from one of the stdfds. */
struct termios oldtios;
ret = lxc_setup_tios(args->ptyfd, &oldtios);
if (ret < 0)
return -1;
/* Create master/slave fd pair for pty. */
pid = fork_pty(&master);
if (pid < 0)
goto err1;
/* Pass windowsize from one of the stdfds to the current masterfd. */
lxc_console_winsz(args->ptyfd, master);
/* Run shell/command on slave side of pty. */
if (pid == 0) {
if (args->command->program)
lxc_attach_run_command(args->command);
else
lxc_attach_run_shell(NULL);
return -1;
}
/*
* For future reference: Must use process_lock() when called from a
* threaded context.
*/
args->ts = lxc_console_sigwinch_init(args->ptyfd, master);
if (!args->ts) {
ret = -1;
goto err2;
}
args->ts->escape = -1;
args->ts->stdoutfd = STDOUT_FILENO;
args->ts->winch_proxy = NULL;
struct lxc_epoll_descr descr;
ret = lxc_mainloop_open(&descr);
if (ret) {
ERROR("failed to create mainloop");
goto err3;
}
/* Register sigwinch handler in mainloop. */
ret = lxc_mainloop_add_handler(&descr, args->ts->sigfd,
lxc_console_cb_sigwinch_fd, args->ts);
if (ret) {
ERROR("failed to add handler for SIGWINCH fd");
goto err4;
}
/* Register i/o callbacks in mainloop. */
ret = lxc_mainloop_add_handler(&descr, args->ts->stdinfd,
lxc_console_cb_tty_stdin, args->ts);
if (ret) {
ERROR("failed to add handler for stdinfd");
goto err4;
}
ret = lxc_mainloop_add_handler(&descr, args->ts->masterfd,
lxc_console_cb_tty_master, args->ts);
if (ret) {
ERROR("failed to add handler for masterfd");
goto err4;
}
ret = lxc_mainloop(&descr, -1);
if (ret) {
ERROR("mainloop returned an error");
goto err4;
}
err4:
lxc_mainloop_close(&descr);
err3:
lxc_console_sigwinch_fini(args->ts);
err2:
close(args->ts->masterfd);
err1:
tcsetattr(args->ptyfd, TCSAFLUSH, &oldtios);
if (pid > 0)
ret = lxc_wait_for_pid_status(pid);
return ret;
}
static int pty_on_host_callback(void *p)
{
struct wrapargs *wrap = p;
close(wrap->console->master);
setsid();
ioctl(wrap->console->slave, TIOCSCTTY, NULL);
if (lxc_console_set_stdfds(wrap->console->slave) < 0)
return -1;
if (wrap->command->program)
lxc_attach_run_command(wrap->command);
else
lxc_attach_run_shell(NULL);
return -1;
}
static int pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
{
int ret = -1;
struct wrapargs *args = wrap;
struct lxc_epoll_descr descr;
struct lxc_conf *conf;
struct lxc_tty_state *ts;
INFO("Trying to allocate a pty on the host");
if (!isatty(args->ptyfd)) {
ERROR("stdin is not a tty");
return -1;
}
conf = c->lxc_conf;
/* Create pty on the host. */
if (lxc_console_create(conf) < 0)
return -1;
ts = conf->console.tty_state;
/* Shift ttys to container. */
if (ttys_shift_ids(conf) < 0) {
ERROR("Failed to shift tty into container");
goto err1;
}
/* Send wrapper function on its way. */
wrap->console = &conf->console;
if (c->attach(c, pty_on_host_callback, wrap, wrap->options, pid) < 0)
goto err1;
close(conf->console.slave); /* Close slave side. */
ret = lxc_mainloop_open(&descr);
if (ret) {
ERROR("failed to create mainloop");
goto err2;
}
/* Register sigwinch handler in mainloop. */
ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
lxc_console_cb_sigwinch_fd, ts);
if (ret) {
ERROR("failed to add handler for SIGWINCH fd");
goto err3;
}
/* Register i/o callbacks in mainloop. */
ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
lxc_console_cb_tty_stdin, ts);
if (ret) {
ERROR("failed to add handler for stdinfd");
goto err3;
}
ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
lxc_console_cb_tty_master, ts);
if (ret) {
ERROR("failed to add handler for masterfd");
goto err3;
}
ret = lxc_mainloop(&descr, -1);
if (ret) {
ERROR("mainloop returned an error");
goto err3;
}
ret = 0;
err3:
lxc_mainloop_close(&descr);
err2:
lxc_console_sigwinch_fini(ts);
err1:
lxc_console_delete(&conf->console);
return ret;
}
int main(int argc, char *argv[])
{
int ret = -1;
pid_t pid; pid_t pid;
lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
lxc_attach_command_t command; lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
ret = lxc_caps_init(); ret = lxc_caps_init();
if (ret) if (ret)
return 1; exit(EXIT_FAILURE);
ret = lxc_arguments_parse(&my_args, argc, argv); ret = lxc_arguments_parse(&my_args, argc, argv);
if (ret) if (ret)
return 1; exit(EXIT_FAILURE);
if (!my_args.log_file) if (!my_args.log_file)
my_args.log_file = "none"; my_args.log_file = "none";
...@@ -207,9 +458,33 @@ int main(int argc, char *argv[]) ...@@ -207,9 +458,33 @@ int main(int argc, char *argv[])
ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority, ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
my_args.progname, my_args.quiet, my_args.lxcpath[0]); my_args.progname, my_args.quiet, my_args.lxcpath[0]);
if (ret) if (ret)
return 1; exit(EXIT_FAILURE);
lxc_log_options_no_override(); lxc_log_options_no_override();
if (geteuid()) {
if (access(my_args.lxcpath[0], O_RDWR) < 0) {
if (!my_args.quiet)
fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
exit(ret);
}
}
struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c)
exit(EXIT_FAILURE);
if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (!c->is_defined(c)) {
fprintf(stderr, "Error: container %s is not defined\n", c->name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (remount_sys_proc) if (remount_sys_proc)
attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
if (elevated_privileges) if (elevated_privileges)
...@@ -220,23 +495,41 @@ int main(int argc, char *argv[]) ...@@ -220,23 +495,41 @@ int main(int argc, char *argv[])
attach_options.extra_env_vars = extra_env; attach_options.extra_env_vars = extra_env;
attach_options.extra_keep_env = extra_keep; attach_options.extra_keep_env = extra_keep;
if (my_args.argc) { struct wrapargs wrap = (struct wrapargs){.command = &command,
command.program = my_args.argv[0]; .options = &attach_options};
command.argv = (char**)my_args.argv; if (my_args.argc > 0) {
ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_command, &command, &attach_options, &pid); wrap.command->program = my_args.argv[0];
wrap.command->argv = (char**)my_args.argv;
}
if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO)) {
if (isatty(STDIN_FILENO))
wrap.ptyfd = STDIN_FILENO;
else if (isatty(STDOUT_FILENO))
wrap.ptyfd = STDOUT_FILENO;
else if (isatty(STDERR_FILENO))
wrap.ptyfd = STDERR_FILENO;
ret = c->attach(c, pty_in_container, &wrap, &attach_options, &pid);
if (ret < 0)
ret = pty_on_host(c, &wrap, &pid);
} else { } else {
ret = lxc_attach(my_args.name, my_args.lxcpath[0], lxc_attach_run_shell, NULL, &attach_options, &pid); if (my_args.argc > 1)
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
else
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
} }
lxc_container_put(c);
if (ret < 0) if (ret < 0)
return 1; exit(EXIT_FAILURE);
ret = lxc_wait_for_pid_status(pid); ret = lxc_wait_for_pid_status(pid);
if (ret < 0) if (ret < 0)
return 1; exit(EXIT_FAILURE);
if (WIFEXITED(ret)) if (WIFEXITED(ret))
return WEXITSTATUS(ret); return WEXITSTATUS(ret);
return 1; exit(EXIT_FAILURE);
} }
...@@ -798,7 +798,7 @@ static int do_start(void *data) ...@@ -798,7 +798,7 @@ static int do_start(void *data)
* setup on its console ie. the pty allocated in lxc_console_create() * setup on its console ie. the pty allocated in lxc_console_create()
* so make sure that that pty is stdin,stdout,stderr. * so make sure that that pty is stdin,stdout,stderr.
*/ */
if (lxc_console_set_stdfds(handler) < 0) if (lxc_console_set_stdfds(handler->conf->console.slave) < 0)
goto out_warn_father; goto out_warn_father;
/* If we mounted a temporary proc, then unmount it now */ /* If we mounted a temporary proc, then unmount it now */
......
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