mirror of
https://github.com/rancher/os.git
synced 2025-09-01 06:40:31 +00:00
move dependencies to vendor
This commit is contained in:
25
vendor/github.com/opencontainers/runc/libcontainer/nsenter/README.md
generated
vendored
Normal file
25
vendor/github.com/opencontainers/runc/libcontainer/nsenter/README.md
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
## nsenter
|
||||
|
||||
The `nsenter` package registers a special init constructor that is called before
|
||||
the Go runtime has a chance to boot. This provides us the ability to `setns` on
|
||||
existing namespaces and avoid the issues that the Go runtime has with multiple
|
||||
threads. This constructor will be called if this package is registered,
|
||||
imported, in your go application.
|
||||
|
||||
The `nsenter` package will `import "C"` and it uses [cgo](https://golang.org/cmd/cgo/)
|
||||
package. In cgo, if the import of "C" is immediately preceded by a comment, that comment,
|
||||
called the preamble, is used as a header when compiling the C parts of the package.
|
||||
So every time we import package `nsenter`, the C code function `nsexec()` would be
|
||||
called. And package `nsenter` is now only imported in Docker execdriver, so every time
|
||||
before we call `execdriver.Exec()`, that C code would run.
|
||||
|
||||
`nsexec()` will first check the environment variable `_LIBCONTAINER_INITPID`
|
||||
which will give the process of the container that should be joined. Namespaces fd will
|
||||
be found from `/proc/[pid]/ns` and set by `setns` syscall.
|
||||
|
||||
And then get the pipe number from `_LIBCONTAINER_INITPIPE`, error message could
|
||||
be transfered through it. If tty is added, `_LIBCONTAINER_CONSOLE_PATH` will
|
||||
have value and start a console for output.
|
||||
|
||||
Finally, `nsexec()` will clone a child process , exit the parent process and let
|
||||
the Go runtime take over.
|
12
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter.go
generated
vendored
Normal file
12
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// +build linux,!gccgo
|
||||
|
||||
package nsenter
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -Wall
|
||||
extern void nsexec();
|
||||
void __attribute__((constructor)) init(void) {
|
||||
nsexec();
|
||||
}
|
||||
*/
|
||||
import "C"
|
25
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_gccgo.go
generated
vendored
Normal file
25
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_gccgo.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// +build linux,gccgo
|
||||
|
||||
package nsenter
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -Wall
|
||||
extern void nsexec();
|
||||
void __attribute__((constructor)) init(void) {
|
||||
nsexec();
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// AlwaysFalse is here to stay false
|
||||
// (and be exported so the compiler doesn't optimize out its reference)
|
||||
var AlwaysFalse bool
|
||||
|
||||
func init() {
|
||||
if AlwaysFalse {
|
||||
// by referencing this C init() in a noop test, it will ensure the compiler
|
||||
// links in the C function.
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65134
|
||||
C.init()
|
||||
}
|
||||
}
|
91
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go
generated
vendored
Normal file
91
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package nsenter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type pid struct {
|
||||
Pid int `json:"Pid"`
|
||||
}
|
||||
|
||||
func TestNsenterAlivePid(t *testing.T) {
|
||||
args := []string{"nsenter-exec"}
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create pipe %v", err)
|
||||
}
|
||||
|
||||
cmd := &exec.Cmd{
|
||||
Path: os.Args[0],
|
||||
Args: args,
|
||||
ExtraFiles: []*os.File{w},
|
||||
Env: []string{fmt.Sprintf("_LIBCONTAINER_INITPID=%d", os.Getpid()), "_LIBCONTAINER_INITPIPE=3"},
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("nsenter failed to start %v", err)
|
||||
}
|
||||
w.Close()
|
||||
|
||||
decoder := json.NewDecoder(r)
|
||||
var pid *pid
|
||||
|
||||
if err := decoder.Decode(&pid); err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
t.Fatalf("nsenter exits with a non-zero exit status")
|
||||
}
|
||||
p, err := os.FindProcess(pid.Pid)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
p.Wait()
|
||||
}
|
||||
|
||||
func TestNsenterInvalidPid(t *testing.T) {
|
||||
args := []string{"nsenter-exec"}
|
||||
|
||||
cmd := &exec.Cmd{
|
||||
Path: os.Args[0],
|
||||
Args: args,
|
||||
Env: []string{"_LIBCONTAINER_INITPID=-1"},
|
||||
}
|
||||
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
t.Fatal("nsenter exits with a zero exit status")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNsenterDeadPid(t *testing.T) {
|
||||
dead_cmd := exec.Command("true")
|
||||
if err := dead_cmd.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
args := []string{"nsenter-exec"}
|
||||
|
||||
cmd := &exec.Cmd{
|
||||
Path: os.Args[0],
|
||||
Args: args,
|
||||
Env: []string{fmt.Sprintf("_LIBCONTAINER_INITPID=%d", dead_cmd.Process.Pid)},
|
||||
}
|
||||
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
t.Fatal("nsenter exits with a zero exit status")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if strings.HasPrefix(os.Args[0], "nsenter-") {
|
||||
os.Exit(0)
|
||||
}
|
||||
return
|
||||
}
|
5
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go
generated
vendored
Normal file
5
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// +build !linux !cgo
|
||||
|
||||
package nsenter
|
||||
|
||||
import "C"
|
190
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
generated
vendored
Normal file
190
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <sys/types.h>
|
||||
#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>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
|
||||
/* All arguments should be above stack, because it grows down */
|
||||
struct clone_arg {
|
||||
/*
|
||||
* Reserve some space for clone() to locate arguments
|
||||
* and retcode in this place
|
||||
*/
|
||||
char stack[4096] __attribute__ ((aligned(8)));
|
||||
char stack_ptr[0];
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
#include "syscall.h"
|
||||
#if defined(__NR_setns) && !defined(SYS_setns)
|
||||
#define SYS_setns __NR_setns
|
||||
#endif
|
||||
#ifdef SYS_setns
|
||||
int setns(int fd, int nstype)
|
||||
{
|
||||
return syscall(SYS_setns, fd, nstype);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int clone_parent(jmp_buf * env) __attribute__ ((noinline));
|
||||
static int clone_parent(jmp_buf * env)
|
||||
{
|
||||
struct clone_arg ca;
|
||||
int child;
|
||||
|
||||
ca.env = env;
|
||||
child = clone(child_func, ca.stack_ptr, CLONE_PARENT | SIGCHLD, &ca);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
void nsexec()
|
||||
{
|
||||
char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" };
|
||||
const int num = sizeof(namespaces) / sizeof(char *);
|
||||
jmp_buf env;
|
||||
char buf[PATH_MAX], *val;
|
||||
int i, tfd, child, len, pipenum, consolefd = -1;
|
||||
pid_t pid;
|
||||
char *console;
|
||||
|
||||
val = getenv("_LIBCONTAINER_INITPID");
|
||||
if (val == NULL)
|
||||
return;
|
||||
|
||||
pid = atoi(val);
|
||||
snprintf(buf, sizeof(buf), "%d", pid);
|
||||
if (strcmp(val, buf)) {
|
||||
pr_perror("Unable to parse _LIBCONTAINER_INITPID");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
val = getenv("_LIBCONTAINER_INITPIPE");
|
||||
if (val == NULL) {
|
||||
pr_perror("Child pipe not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pipenum = atoi(val);
|
||||
snprintf(buf, sizeof(buf), "%d", pipenum);
|
||||
if (strcmp(val, buf)) {
|
||||
pr_perror("Unable to parse _LIBCONTAINER_INITPIPE");
|
||||
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);
|
||||
if (tfd == -1) {
|
||||
pr_perror("Failed to open \"%s\"", buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
/* Symlinks on all namespaces exist for dead processes, but they can't be opened */
|
||||
if (fstatat(tfd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) == -1) {
|
||||
// Ignore nonexistent namespaces.
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = openat(tfd, namespaces[i], O_RDONLY);
|
||||
if (fd == -1) {
|
||||
pr_perror("Failed to open ns file %s for ns %s", buf,
|
||||
namespaces[i]);
|
||||
exit(1);
|
||||
}
|
||||
// Set the namespace.
|
||||
if (setns(fd, 0) == -1) {
|
||||
pr_perror("Failed to setns for %s", namespaces[i]);
|
||||
exit(1);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (setjmp(env) == 1) {
|
||||
// Child
|
||||
|
||||
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 (dup3(consolefd, STDIN_FILENO, 0) != STDIN_FILENO) {
|
||||
pr_perror("Failed to dup 0");
|
||||
exit(1);
|
||||
}
|
||||
if (dup3(consolefd, STDOUT_FILENO, 0) != STDOUT_FILENO) {
|
||||
pr_perror("Failed to dup 1");
|
||||
exit(1);
|
||||
}
|
||||
if (dup3(consolefd, STDERR_FILENO, 0) != STDERR_FILENO) {
|
||||
pr_perror("Failed to dup 2");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
// Finish executing, let the Go runtime take over.
|
||||
return;
|
||||
}
|
||||
// Parent
|
||||
|
||||
// We must fork to actually enter the PID namespace, use CLONE_PARENT
|
||||
// so the child can have the right parent, and we don't need to forward
|
||||
// the child's exit code or resend its death signal.
|
||||
child = clone_parent(&env);
|
||||
if (child < 0) {
|
||||
pr_perror("Unable to fork");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", child);
|
||||
|
||||
if (write(pipenum, buf, len) != len) {
|
||||
pr_perror("Unable to send a child pid");
|
||||
kill(child, SIGKILL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
Reference in New Issue
Block a user