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()),
|
||||
"_LIBCONTAINER_INITTYPE=setns",
|
||||
)
|
||||
|
||||
if p.consolePath != "" {
|
||||
cmd.Env = append(cmd.Env, "_LIBCONTAINER_CONSOLE_PATH="+p.consolePath)
|
||||
}
|
||||
|
||||
// TODO: set on container for process management
|
||||
return &setnsProcess{
|
||||
cmd: cmd,
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
||||
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/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
@ -27,14 +28,14 @@ struct clone_arg {
|
|||
jmp_buf *env;
|
||||
};
|
||||
|
||||
#define pr_perror(fmt, ...) fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__)
|
||||
|
||||
static int child_func(void *_arg)
|
||||
{
|
||||
struct clone_arg *arg = (struct clone_arg *)_arg;
|
||||
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)
|
||||
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14
|
||||
#define _GNU_SOURCE
|
||||
|
@ -65,8 +66,9 @@ void nsexec()
|
|||
const int num = sizeof(namespaces) / sizeof(char *);
|
||||
jmp_buf env;
|
||||
char buf[PATH_MAX], *val;
|
||||
int i, tfd, child, len;
|
||||
int i, tfd, child, len, consolefd = -1;
|
||||
pid_t pid;
|
||||
char *console;
|
||||
|
||||
val = getenv("_LIBCONTAINER_INITPID");
|
||||
if (val == NULL)
|
||||
|
@ -79,6 +81,15 @@ void nsexec()
|
|||
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 */
|
||||
snprintf(buf, PATH_MAX - 1, "/proc/%d/ns", pid);
|
||||
tfd = open(buf, O_DIRECTORY | O_RDONLY);
|
||||
|
@ -113,6 +124,28 @@ void nsexec()
|
|||
}
|
||||
|
||||
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.
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue