Add tty support for setnsProcess
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
This commit is contained in:
parent
1c9de5b4d2
commit
a9644c209f
|
@ -175,6 +175,11 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe,
|
||||||
fmt.Sprintf("_LIBCONTAINER_INITPID=%d", c.initProcess.pid()),
|
fmt.Sprintf("_LIBCONTAINER_INITPID=%d", c.initProcess.pid()),
|
||||||
"_LIBCONTAINER_INITTYPE=setns",
|
"_LIBCONTAINER_INITTYPE=setns",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if p.consolePath != "" {
|
||||||
|
cmd.Env = append(cmd.Env, "_LIBCONTAINER_CONSOLE_PATH="+p.consolePath)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: set on container for process management
|
// TODO: set on container for process management
|
||||||
return &setnsProcess{
|
return &setnsProcess{
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
)
|
)
|
||||||
|
@ -173,3 +176,72 @@ func TestExecInError(t *testing.T) {
|
||||||
t.Fatalf("Should be error about not found executable, got %s", err)
|
t.Fatalf("Should be error about not found executable, got %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExecInTTY(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer remove(rootfs)
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
container, err := newContainer(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
// Execute a first process in the container
|
||||||
|
stdinR, stdinW, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
process := &libcontainer.Process{
|
||||||
|
Args: []string{"cat"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: stdinR,
|
||||||
|
}
|
||||||
|
err = container.Start(process)
|
||||||
|
stdinR.Close()
|
||||||
|
defer stdinW.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
ps := &libcontainer.Process{
|
||||||
|
Args: []string{"ps"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
}
|
||||||
|
console, err := ps.NewConsole(0)
|
||||||
|
copy := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
io.Copy(&stdout, console)
|
||||||
|
close(copy)
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = container.Start(ps)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatal("Waiting for copy timed out")
|
||||||
|
case <-copy:
|
||||||
|
}
|
||||||
|
if _, err := ps.Wait(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
stdinW.Close()
|
||||||
|
if _, err := process.Wait(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
out := stdout.String()
|
||||||
|
if !strings.Contains(out, "cat") || !strings.Contains(string(out), "ps") {
|
||||||
|
t.Fatalf("unexpected running process, output %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
@ -27,14 +28,14 @@ struct clone_arg {
|
||||||
jmp_buf *env;
|
jmp_buf *env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define pr_perror(fmt, ...) fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__)
|
||||||
|
|
||||||
static int child_func(void *_arg)
|
static int child_func(void *_arg)
|
||||||
{
|
{
|
||||||
struct clone_arg *arg = (struct clone_arg *)_arg;
|
struct clone_arg *arg = (struct clone_arg *)_arg;
|
||||||
longjmp(*arg->env, 1);
|
longjmp(*arg->env, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define pr_perror(fmt, ...) fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__)
|
|
||||||
|
|
||||||
// Use raw setns syscall for versions of glibc that don't include it (namely glibc-2.12)
|
// Use raw setns syscall for versions of glibc that don't include it (namely glibc-2.12)
|
||||||
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14
|
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
@ -65,8 +66,9 @@ void nsexec()
|
||||||
const int num = sizeof(namespaces) / sizeof(char *);
|
const int num = sizeof(namespaces) / sizeof(char *);
|
||||||
jmp_buf env;
|
jmp_buf env;
|
||||||
char buf[PATH_MAX], *val;
|
char buf[PATH_MAX], *val;
|
||||||
int i, tfd, child, len;
|
int i, tfd, child, len, consolefd = -1;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
char *console;
|
||||||
|
|
||||||
val = getenv("_LIBCONTAINER_INITPID");
|
val = getenv("_LIBCONTAINER_INITPID");
|
||||||
if (val == NULL)
|
if (val == NULL)
|
||||||
|
@ -79,6 +81,15 @@ void nsexec()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console = getenv("_LIBCONTAINER_CONSOLE_PATH");
|
||||||
|
if (console != NULL) {
|
||||||
|
consolefd = open(console, O_RDWR);
|
||||||
|
if (consolefd < 0) {
|
||||||
|
pr_perror("Failed to open console %s", console);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check that the specified process exists */
|
/* Check that the specified process exists */
|
||||||
snprintf(buf, PATH_MAX - 1, "/proc/%d/ns", pid);
|
snprintf(buf, PATH_MAX - 1, "/proc/%d/ns", pid);
|
||||||
tfd = open(buf, O_DIRECTORY | O_RDONLY);
|
tfd = open(buf, O_DIRECTORY | O_RDONLY);
|
||||||
|
@ -113,6 +124,28 @@ void nsexec()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setjmp(env) == 1) {
|
if (setjmp(env) == 1) {
|
||||||
|
if (setsid() == -1) {
|
||||||
|
pr_perror("setsid failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (consolefd != -1) {
|
||||||
|
if (ioctl(consolefd, TIOCSCTTY, 0) == -1) {
|
||||||
|
pr_perror("ioctl TIOCSCTTY failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (dup2(consolefd, STDIN_FILENO) != STDIN_FILENO) {
|
||||||
|
pr_perror("Failed to dup 0");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (dup2(consolefd, STDOUT_FILENO) != STDOUT_FILENO) {
|
||||||
|
pr_perror("Failed to dup 1");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (dup2(consolefd, STDERR_FILENO) != STDERR_FILENO) {
|
||||||
|
pr_perror("Failed to dup 2");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Finish executing, let the Go runtime take over.
|
// Finish executing, let the Go runtime take over.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue