mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Use argv0 as reexec implementation for dockerinit
This changes the way the exec drivers work by not specifing a -driver flag on reexec. For each of the exec drivers they register their own functions that will be matched aginst the argv 0 on exec and called if they match. This also allows any functionality to be added to docker so that the binary can be reexec'd and any type of function can be called. I moved the flag parsing on docker exec to the specific initializers so that the implementations do not bleed into one another. This also allows for more flexability within reexec initializers to specify their own flags and options. Signed-off-by: Michael Crosby <michael@docker.com>
This commit is contained in:
		
							parent
							
								
									e033425f0b
								
							
						
					
					
						commit
						7321067176
					
				
					 13 changed files with 208 additions and 185 deletions
				
			
		| 
						 | 
					@ -20,49 +20,7 @@ var (
 | 
				
			||||||
	ErrDriverNotFound          = errors.New("The requested docker init has not been found")
 | 
						ErrDriverNotFound          = errors.New("The requested docker init has not been found")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var dockerInitFcts map[string]InitFunc
 | 
					type StartCallback func(*Command)
 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	StartCallback func(*Command)
 | 
					 | 
				
			||||||
	InitFunc      func(i *InitArgs) error
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func RegisterInitFunc(name string, fct InitFunc) error {
 | 
					 | 
				
			||||||
	if dockerInitFcts == nil {
 | 
					 | 
				
			||||||
		dockerInitFcts = make(map[string]InitFunc)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if _, ok := dockerInitFcts[name]; ok {
 | 
					 | 
				
			||||||
		return ErrDriverAlreadyRegistered
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	dockerInitFcts[name] = fct
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func GetInitFunc(name string) (InitFunc, error) {
 | 
					 | 
				
			||||||
	fct, ok := dockerInitFcts[name]
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		return nil, ErrDriverNotFound
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return fct, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Args provided to the init function for a driver
 | 
					 | 
				
			||||||
type InitArgs struct {
 | 
					 | 
				
			||||||
	User       string
 | 
					 | 
				
			||||||
	Gateway    string
 | 
					 | 
				
			||||||
	Ip         string
 | 
					 | 
				
			||||||
	WorkDir    string
 | 
					 | 
				
			||||||
	Privileged bool
 | 
					 | 
				
			||||||
	Env        []string
 | 
					 | 
				
			||||||
	Args       []string
 | 
					 | 
				
			||||||
	Mtu        int
 | 
					 | 
				
			||||||
	Driver     string
 | 
					 | 
				
			||||||
	Console    string
 | 
					 | 
				
			||||||
	Pipe       int
 | 
					 | 
				
			||||||
	Root       string
 | 
					 | 
				
			||||||
	CapAdd     string
 | 
					 | 
				
			||||||
	CapDrop    string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Driver specific information based on
 | 
					// Driver specific information based on
 | 
				
			||||||
// processes registered with the driver
 | 
					// processes registered with the driver
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,12 +5,10 @@ import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
| 
						 | 
					@ -27,34 +25,6 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DriverName = "lxc"
 | 
					const DriverName = "lxc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
 | 
					 | 
				
			||||||
		runtime.LockOSThread()
 | 
					 | 
				
			||||||
		if err := setupEnv(args); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err := setupHostname(args); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err := setupNetworking(args); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err := finalizeNamespace(args); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		path, err := exec.LookPath(args.Args[0])
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Printf("Unable to locate %v", args.Args[0])
 | 
					 | 
				
			||||||
			os.Exit(127)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("dockerinit unable to execute %s - %s", path, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		panic("Unreachable")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type driver struct {
 | 
					type driver struct {
 | 
				
			||||||
	root       string // root path for the driver to use
 | 
						root       string // root path for the driver to use
 | 
				
			||||||
	initPath   string
 | 
						initPath   string
 | 
				
			||||||
| 
						 | 
					@ -67,6 +37,7 @@ func NewDriver(root, initPath string, apparmor bool) (*driver, error) {
 | 
				
			||||||
	if err := linkLxcStart(root); err != nil {
 | 
						if err := linkLxcStart(root); err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &driver{
 | 
						return &driver{
 | 
				
			||||||
		apparmor:   apparmor,
 | 
							apparmor:   apparmor,
 | 
				
			||||||
		root:       root,
 | 
							root:       root,
 | 
				
			||||||
| 
						 | 
					@ -108,8 +79,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 | 
				
			||||||
		"-f", configPath,
 | 
							"-f", configPath,
 | 
				
			||||||
		"--",
 | 
							"--",
 | 
				
			||||||
		c.InitPath,
 | 
							c.InitPath,
 | 
				
			||||||
		"-driver",
 | 
					 | 
				
			||||||
		DriverName,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if c.Network.Interface != nil {
 | 
						if c.Network.Interface != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,19 +2,116 @@ package lxc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/docker/daemon/execdriver"
 | 
						"github.com/docker/docker/reexec"
 | 
				
			||||||
	"github.com/docker/libcontainer/netlink"
 | 
						"github.com/docker/libcontainer/netlink"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Args provided to the init function for a driver
 | 
				
			||||||
 | 
					type InitArgs struct {
 | 
				
			||||||
 | 
						User       string
 | 
				
			||||||
 | 
						Gateway    string
 | 
				
			||||||
 | 
						Ip         string
 | 
				
			||||||
 | 
						WorkDir    string
 | 
				
			||||||
 | 
						Privileged bool
 | 
				
			||||||
 | 
						Env        []string
 | 
				
			||||||
 | 
						Args       []string
 | 
				
			||||||
 | 
						Mtu        int
 | 
				
			||||||
 | 
						Console    string
 | 
				
			||||||
 | 
						Pipe       int
 | 
				
			||||||
 | 
						Root       string
 | 
				
			||||||
 | 
						CapAdd     string
 | 
				
			||||||
 | 
						CapDrop    string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						// like always lxc requires a hack to get this to work
 | 
				
			||||||
 | 
						reexec.Register("/.dockerinit", dockerInititalizer)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func dockerInititalizer() {
 | 
				
			||||||
 | 
						initializer()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// initializer is the lxc driver's init function that is run inside the namespace to setup
 | 
				
			||||||
 | 
					// additional configurations
 | 
				
			||||||
 | 
					func initializer() {
 | 
				
			||||||
 | 
						runtime.LockOSThread()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						args := getArgs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := setupNamespace(args); err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setupNamespace(args *InitArgs) error {
 | 
				
			||||||
 | 
						if err := setupEnv(args); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := setupHostname(args); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := setupNetworking(args); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := finalizeNamespace(args); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						path, err := exec.LookPath(args.Args[0])
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Unable to locate %v", args.Args[0])
 | 
				
			||||||
 | 
							os.Exit(127)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("dockerinit unable to execute %s - %s", path, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getArgs() *InitArgs {
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							// Get cmdline arguments
 | 
				
			||||||
 | 
							user       = flag.String("u", "", "username or uid")
 | 
				
			||||||
 | 
							gateway    = flag.String("g", "", "gateway address")
 | 
				
			||||||
 | 
							ip         = flag.String("i", "", "ip address")
 | 
				
			||||||
 | 
							workDir    = flag.String("w", "", "workdir")
 | 
				
			||||||
 | 
							privileged = flag.Bool("privileged", false, "privileged mode")
 | 
				
			||||||
 | 
							mtu        = flag.Int("mtu", 1500, "interface mtu")
 | 
				
			||||||
 | 
							capAdd     = flag.String("cap-add", "", "capabilities to add")
 | 
				
			||||||
 | 
							capDrop    = flag.String("cap-drop", "", "capabilities to drop")
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &InitArgs{
 | 
				
			||||||
 | 
							User:       *user,
 | 
				
			||||||
 | 
							Gateway:    *gateway,
 | 
				
			||||||
 | 
							Ip:         *ip,
 | 
				
			||||||
 | 
							WorkDir:    *workDir,
 | 
				
			||||||
 | 
							Privileged: *privileged,
 | 
				
			||||||
 | 
							Args:       flag.Args(),
 | 
				
			||||||
 | 
							Mtu:        *mtu,
 | 
				
			||||||
 | 
							CapAdd:     *capAdd,
 | 
				
			||||||
 | 
							CapDrop:    *capDrop,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clear environment pollution introduced by lxc-start
 | 
					// Clear environment pollution introduced by lxc-start
 | 
				
			||||||
func setupEnv(args *execdriver.InitArgs) error {
 | 
					func setupEnv(args *InitArgs) error {
 | 
				
			||||||
	// Get env
 | 
						// Get env
 | 
				
			||||||
	var env []string
 | 
						var env []string
 | 
				
			||||||
	content, err := ioutil.ReadFile(".dockerenv")
 | 
						content, err := ioutil.ReadFile(".dockerenv")
 | 
				
			||||||
| 
						 | 
					@ -41,7 +138,7 @@ func setupEnv(args *execdriver.InitArgs) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setupHostname(args *execdriver.InitArgs) error {
 | 
					func setupHostname(args *InitArgs) error {
 | 
				
			||||||
	hostname := getEnv(args, "HOSTNAME")
 | 
						hostname := getEnv(args, "HOSTNAME")
 | 
				
			||||||
	if hostname == "" {
 | 
						if hostname == "" {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
| 
						 | 
					@ -50,7 +147,7 @@ func setupHostname(args *execdriver.InitArgs) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Setup networking
 | 
					// Setup networking
 | 
				
			||||||
func setupNetworking(args *execdriver.InitArgs) error {
 | 
					func setupNetworking(args *InitArgs) error {
 | 
				
			||||||
	if args.Ip != "" {
 | 
						if args.Ip != "" {
 | 
				
			||||||
		// eth0
 | 
							// eth0
 | 
				
			||||||
		iface, err := net.InterfaceByName("eth0")
 | 
							iface, err := net.InterfaceByName("eth0")
 | 
				
			||||||
| 
						 | 
					@ -95,7 +192,7 @@ func setupNetworking(args *execdriver.InitArgs) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Setup working directory
 | 
					// Setup working directory
 | 
				
			||||||
func setupWorkingDirectory(args *execdriver.InitArgs) error {
 | 
					func setupWorkingDirectory(args *InitArgs) error {
 | 
				
			||||||
	if args.WorkDir == "" {
 | 
						if args.WorkDir == "" {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -105,7 +202,7 @@ func setupWorkingDirectory(args *execdriver.InitArgs) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getEnv(args *execdriver.InitArgs, key string) string {
 | 
					func getEnv(args *InitArgs, key string) string {
 | 
				
			||||||
	for _, kv := range args.Env {
 | 
						for _, kv := range args.Env {
 | 
				
			||||||
		parts := strings.SplitN(kv, "=", 2)
 | 
							parts := strings.SplitN(kv, "=", 2)
 | 
				
			||||||
		if parts[0] == key && len(parts) == 2 {
 | 
							if parts[0] == key && len(parts) == 2 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ func setHostname(hostname string) error {
 | 
				
			||||||
	return syscall.Sethostname([]byte(hostname))
 | 
						return syscall.Sethostname([]byte(hostname))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func finalizeNamespace(args *execdriver.InitArgs) error {
 | 
					func finalizeNamespace(args *InitArgs) error {
 | 
				
			||||||
	if err := utils.CloseExecFrom(3); err != nil {
 | 
						if err := utils.CloseExecFrom(3); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,6 @@ import (
 | 
				
			||||||
	"github.com/docker/libcontainer/cgroups/systemd"
 | 
						"github.com/docker/libcontainer/cgroups/systemd"
 | 
				
			||||||
	consolepkg "github.com/docker/libcontainer/console"
 | 
						consolepkg "github.com/docker/libcontainer/console"
 | 
				
			||||||
	"github.com/docker/libcontainer/namespaces"
 | 
						"github.com/docker/libcontainer/namespaces"
 | 
				
			||||||
	"github.com/docker/libcontainer/syncpipe"
 | 
					 | 
				
			||||||
	"github.com/docker/libcontainer/system"
 | 
						"github.com/docker/libcontainer/system"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,38 +30,6 @@ const (
 | 
				
			||||||
	Version    = "0.2"
 | 
						Version    = "0.2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
 | 
					 | 
				
			||||||
		var container *libcontainer.Config
 | 
					 | 
				
			||||||
		f, err := os.Open(filepath.Join(args.Root, "container.json"))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err := json.NewDecoder(f).Decode(&container); err != nil {
 | 
					 | 
				
			||||||
			f.Close()
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		f.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rootfs, err := os.Getwd()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(args.Pipe))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err := namespaces.Init(container, rootfs, args.Console, syncPipe, args.Args); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type activeContainer struct {
 | 
					type activeContainer struct {
 | 
				
			||||||
	container *libcontainer.Config
 | 
						container *libcontainer.Config
 | 
				
			||||||
	cmd       *exec.Cmd
 | 
						cmd       *exec.Cmd
 | 
				
			||||||
| 
						 | 
					@ -133,13 +100,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return namespaces.Exec(container, c.Stdin, c.Stdout, c.Stderr, c.Console, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {
 | 
						return namespaces.Exec(container, c.Stdin, c.Stdout, c.Stderr, c.Console, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {
 | 
				
			||||||
		// we need to join the rootfs because namespaces will setup the rootfs and chroot
 | 
					 | 
				
			||||||
		initPath := filepath.Join(c.Rootfs, c.InitPath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		c.Path = d.initPath
 | 
							c.Path = d.initPath
 | 
				
			||||||
		c.Args = append([]string{
 | 
							c.Args = append([]string{
 | 
				
			||||||
			initPath,
 | 
								DriverName,
 | 
				
			||||||
			"-driver", DriverName,
 | 
					 | 
				
			||||||
			"-console", console,
 | 
								"-console", console,
 | 
				
			||||||
			"-pipe", "3",
 | 
								"-pipe", "3",
 | 
				
			||||||
			"-root", filepath.Join(d.root, c.ID),
 | 
								"-root", filepath.Join(d.root, c.ID),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										65
									
								
								daemon/execdriver/native/init.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								daemon/execdriver/native/init.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,65 @@
 | 
				
			||||||
 | 
					// +build linux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package native
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"flag"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/docker/reexec"
 | 
				
			||||||
 | 
						"github.com/docker/libcontainer"
 | 
				
			||||||
 | 
						"github.com/docker/libcontainer/namespaces"
 | 
				
			||||||
 | 
						"github.com/docker/libcontainer/syncpipe"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						reexec.Register(DriverName, initializer)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initializer() {
 | 
				
			||||||
 | 
						runtime.LockOSThread()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							pipe    = flag.Int("pipe", 0, "sync pipe fd")
 | 
				
			||||||
 | 
							console = flag.String("console", "", "console (pty slave) path")
 | 
				
			||||||
 | 
							root    = flag.String("root", ".", "root path for configuration files")
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var container *libcontainer.Config
 | 
				
			||||||
 | 
						f, err := os.Open(filepath.Join(*root, "container.json"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							writeError(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := json.NewDecoder(f).Decode(&container); err != nil {
 | 
				
			||||||
 | 
							f.Close()
 | 
				
			||||||
 | 
							writeError(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						f.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rootfs, err := os.Getwd()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							writeError(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(*pipe))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							writeError(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := namespaces.Init(container, rootfs, *console, syncPipe, flag.Args()); err != nil {
 | 
				
			||||||
 | 
							writeError(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						panic("Unreachable")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func writeError(err error) {
 | 
				
			||||||
 | 
						fmt.Sprint(os.Stderr, err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,6 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CanDaemon = false
 | 
					const CanDaemon = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func mainSysinit() {
 | 
					 | 
				
			||||||
	log.Fatal("This is a client-only binary - running it as 'dockerinit' is not supported.")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func mainDaemon() {
 | 
					func mainDaemon() {
 | 
				
			||||||
	log.Fatal("This is a client-only binary - running the Docker daemon is not supported.")
 | 
						log.Fatal("This is a client-only binary - running the Docker daemon is not supported.")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,20 +7,16 @@ import (
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/docker/builtins"
 | 
						"github.com/docker/docker/builtins"
 | 
				
			||||||
 | 
						_ "github.com/docker/docker/daemon/execdriver/lxc"
 | 
				
			||||||
 | 
						_ "github.com/docker/docker/daemon/execdriver/native"
 | 
				
			||||||
	"github.com/docker/docker/dockerversion"
 | 
						"github.com/docker/docker/dockerversion"
 | 
				
			||||||
	"github.com/docker/docker/engine"
 | 
						"github.com/docker/docker/engine"
 | 
				
			||||||
	flag "github.com/docker/docker/pkg/mflag"
 | 
						flag "github.com/docker/docker/pkg/mflag"
 | 
				
			||||||
	"github.com/docker/docker/pkg/signal"
 | 
						"github.com/docker/docker/pkg/signal"
 | 
				
			||||||
	"github.com/docker/docker/sysinit"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CanDaemon = true
 | 
					const CanDaemon = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func mainSysinit() {
 | 
					 | 
				
			||||||
	// Running in init mode
 | 
					 | 
				
			||||||
	sysinit.SysInit()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func mainDaemon() {
 | 
					func mainDaemon() {
 | 
				
			||||||
	if flag.NArg() != 0 {
 | 
						if flag.NArg() != 0 {
 | 
				
			||||||
		flag.Usage()
 | 
							flag.Usage()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@ import (
 | 
				
			||||||
	"github.com/docker/docker/api/client"
 | 
						"github.com/docker/docker/api/client"
 | 
				
			||||||
	"github.com/docker/docker/dockerversion"
 | 
						"github.com/docker/docker/dockerversion"
 | 
				
			||||||
	flag "github.com/docker/docker/pkg/mflag"
 | 
						flag "github.com/docker/docker/pkg/mflag"
 | 
				
			||||||
 | 
						"github.com/docker/docker/reexec"
 | 
				
			||||||
	"github.com/docker/docker/utils"
 | 
						"github.com/docker/docker/utils"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,8 +24,7 @@ const (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	if selfPath := utils.SelfPath(); strings.Contains(selfPath, ".dockerinit") {
 | 
						if reexec.Init() {
 | 
				
			||||||
		mainSysinit()
 | 
					 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,12 @@
 | 
				
			||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/docker/docker/sysinit"
 | 
						_ "github.com/docker/docker/daemon/execdriver/lxc"
 | 
				
			||||||
 | 
						_ "github.com/docker/docker/daemon/execdriver/native"
 | 
				
			||||||
 | 
						"github.com/docker/docker/reexec"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	// Running in init mode
 | 
						// Running in init mode
 | 
				
			||||||
	sysinit.SysInit()
 | 
						reexec.Init()
 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								reexec/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								reexec/README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					## reexec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `reexec` package facilitates the busybox style reexec of the docker binary that we require because 
 | 
				
			||||||
 | 
					of the forking limitations of using Go.  Handlers can be registered with a name and the argv 0 of 
 | 
				
			||||||
 | 
					the exec of the binary will be used to find and execute custom init paths.
 | 
				
			||||||
							
								
								
									
										23
									
								
								reexec/reexec.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								reexec/reexec.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					package reexec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var registeredInitializers = make(map[string]func())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Register adds an initialization func under the specified name
 | 
				
			||||||
 | 
					func Register(name string, initializer func()) {
 | 
				
			||||||
 | 
						registeredInitializers[name] = initializer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Init is called as the first part of the exec process and returns true if an
 | 
				
			||||||
 | 
					// initialization function was called.
 | 
				
			||||||
 | 
					func Init() bool {
 | 
				
			||||||
 | 
						initializer, exists := registeredInitializers[os.Args[0]]
 | 
				
			||||||
 | 
						if exists {
 | 
				
			||||||
 | 
							initializer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,25 +1,11 @@
 | 
				
			||||||
package sysinit
 | 
					package sysinit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"flag"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/docker/docker/daemon/execdriver"
 | 
					 | 
				
			||||||
	_ "github.com/docker/docker/daemon/execdriver/lxc"
 | 
					 | 
				
			||||||
	_ "github.com/docker/docker/daemon/execdriver/native"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func executeProgram(args *execdriver.InitArgs) error {
 | 
					 | 
				
			||||||
	dockerInitFct, err := execdriver.GetInitFunc(args.Driver)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return dockerInitFct(args)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Sys Init code
 | 
					// Sys Init code
 | 
				
			||||||
// This code is run INSIDE the container and is responsible for setting
 | 
					// This code is run INSIDE the container and is responsible for setting
 | 
				
			||||||
// up the environment before running the actual process
 | 
					// up the environment before running the actual process
 | 
				
			||||||
| 
						 | 
					@ -33,40 +19,4 @@ func SysInit() {
 | 
				
			||||||
		os.Exit(1)
 | 
							os.Exit(1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
					 | 
				
			||||||
		// Get cmdline arguments
 | 
					 | 
				
			||||||
		user       = flag.String("u", "", "username or uid")
 | 
					 | 
				
			||||||
		gateway    = flag.String("g", "", "gateway address")
 | 
					 | 
				
			||||||
		ip         = flag.String("i", "", "ip address")
 | 
					 | 
				
			||||||
		workDir    = flag.String("w", "", "workdir")
 | 
					 | 
				
			||||||
		privileged = flag.Bool("privileged", false, "privileged mode")
 | 
					 | 
				
			||||||
		mtu        = flag.Int("mtu", 1500, "interface mtu")
 | 
					 | 
				
			||||||
		driver     = flag.String("driver", "", "exec driver")
 | 
					 | 
				
			||||||
		pipe       = flag.Int("pipe", 0, "sync pipe fd")
 | 
					 | 
				
			||||||
		console    = flag.String("console", "", "console (pty slave) path")
 | 
					 | 
				
			||||||
		root       = flag.String("root", ".", "root path for configuration files")
 | 
					 | 
				
			||||||
		capAdd     = flag.String("cap-add", "", "capabilities to add")
 | 
					 | 
				
			||||||
		capDrop    = flag.String("cap-drop", "", "capabilities to drop")
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	flag.Parse()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	args := &execdriver.InitArgs{
 | 
					 | 
				
			||||||
		User:       *user,
 | 
					 | 
				
			||||||
		Gateway:    *gateway,
 | 
					 | 
				
			||||||
		Ip:         *ip,
 | 
					 | 
				
			||||||
		WorkDir:    *workDir,
 | 
					 | 
				
			||||||
		Privileged: *privileged,
 | 
					 | 
				
			||||||
		Args:       flag.Args(),
 | 
					 | 
				
			||||||
		Mtu:        *mtu,
 | 
					 | 
				
			||||||
		Driver:     *driver,
 | 
					 | 
				
			||||||
		Console:    *console,
 | 
					 | 
				
			||||||
		Pipe:       *pipe,
 | 
					 | 
				
			||||||
		Root:       *root,
 | 
					 | 
				
			||||||
		CapAdd:     *capAdd,
 | 
					 | 
				
			||||||
		CapDrop:    *capDrop,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := executeProgram(args); err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue