Browse Source

Update runc to v0.0.3

This fixes criu behavior with mounted cgroups.
It includes also update of go-systemd dependecy.

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Alexander Morozov 10 years ago
parent
commit
a4ddf0e362
26 changed files with 597 additions and 295 deletions
  1. 2 2
      hack/vendor.sh
  2. 16 20
      vendor/src/github.com/coreos/go-systemd/activation/files.go
  3. 21 22
      vendor/src/github.com/coreos/go-systemd/activation/listeners.go
  4. 37 0
      vendor/src/github.com/coreos/go-systemd/activation/packetconns.go
  5. 109 50
      vendor/src/github.com/coreos/go-systemd/dbus/dbus.go
  6. 69 55
      vendor/src/github.com/coreos/go-systemd/dbus/methods.go
  7. 13 15
      vendor/src/github.com/coreos/go-systemd/dbus/properties.go
  8. 20 6
      vendor/src/github.com/coreos/go-systemd/dbus/set.go
  9. 37 38
      vendor/src/github.com/coreos/go-systemd/dbus/subscription.go
  10. 28 3
      vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go
  11. 13 15
      vendor/src/github.com/coreos/go-systemd/journal/send.go
  12. 33 0
      vendor/src/github.com/coreos/go-systemd/util/util.go
  13. 2 2
      vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go
  14. 1 1
      vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
  15. 1 1
      vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
  16. 18 18
      vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go
  17. 4 0
      vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
  18. 10 0
      vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go
  19. 8 0
      vendor/src/github.com/opencontainers/runc/libcontainer/container.go
  20. 63 23
      vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go
  21. 1 1
      vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go
  22. 1 1
      vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go
  23. 5 1
      vendor/src/github.com/opencontainers/runc/libcontainer/restored_process.go
  24. 69 20
      vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go
  25. 11 0
      vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go
  26. 5 1
      vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go

+ 2 - 2
hack/vendor.sh

@@ -44,9 +44,9 @@ clone git github.com/endophage/gotuf 89ceb27829b9353dfee5ccccf7a3a9bb77008b05
 clone git github.com/tent/canonical-json-go 96e4ba3a7613a1216cbd1badca4efe382adea337
 clone git github.com/tent/canonical-json-go 96e4ba3a7613a1216cbd1badca4efe382adea337
 clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
 clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
 
 
-clone git github.com/opencontainers/runc v0.0.2 # libcontainer
+clone git github.com/opencontainers/runc v0.0.3 # libcontainer
 # libcontainer deps (see src/github.com/docker/libcontainer/update-vendor.sh)
 # libcontainer deps (see src/github.com/docker/libcontainer/update-vendor.sh)
-clone git github.com/coreos/go-systemd v2
+clone git github.com/coreos/go-systemd v3
 clone git github.com/godbus/dbus v2
 clone git github.com/godbus/dbus v2
 clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49fb
 clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49fb
 clone git github.com/golang/protobuf 655cdfa588ea
 clone git github.com/golang/protobuf 655cdfa588ea

+ 16 - 20
vendor/src/github.com/coreos/go-systemd/activation/files.go

@@ -1,18 +1,16 @@
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 // Package activation implements primitives for systemd socket activation.
 // Package activation implements primitives for systemd socket activation.
 package activation
 package activation
@@ -30,10 +28,8 @@ const (
 
 
 func Files(unsetEnv bool) []*os.File {
 func Files(unsetEnv bool) []*os.File {
 	if unsetEnv {
 	if unsetEnv {
-		// there is no way to unset env in golang os package for now
-		// https://code.google.com/p/go/issues/detail?id=6423
-		defer os.Setenv("LISTEN_PID", "")
-		defer os.Setenv("LISTEN_FDS", "")
+		defer os.Unsetenv("LISTEN_PID")
+		defer os.Unsetenv("LISTEN_FDS")
 	}
 	}
 
 
 	pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
 	pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
@@ -46,7 +42,7 @@ func Files(unsetEnv bool) []*os.File {
 		return nil
 		return nil
 	}
 	}
 
 
-	var files []*os.File
+	files := make([]*os.File, 0, nfds)
 	for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
 	for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
 		syscall.CloseOnExec(fd)
 		syscall.CloseOnExec(fd)
 		files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
 		files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))

+ 21 - 22
vendor/src/github.com/coreos/go-systemd/activation/listeners.go

@@ -1,38 +1,37 @@
-/*
-Copyright 2014 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 package activation
 package activation
 
 
 import (
 import (
-	"fmt"
 	"net"
 	"net"
 )
 )
 
 
-// Listeners returns net.Listeners for all socket activated fds passed to this process.
+// Listeners returns a slice containing a net.Listener for each matching socket type
+// passed to this process.
+//
+// The order of the file descriptors is preserved in the returned slice.
+// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
+// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener}
 func Listeners(unsetEnv bool) ([]net.Listener, error) {
 func Listeners(unsetEnv bool) ([]net.Listener, error) {
 	files := Files(unsetEnv)
 	files := Files(unsetEnv)
 	listeners := make([]net.Listener, len(files))
 	listeners := make([]net.Listener, len(files))
 
 
 	for i, f := range files {
 	for i, f := range files {
-		var err error
-		listeners[i], err = net.FileListener(f)
-		if err != nil {
-			return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error())
+		if pc, err := net.FileListener(f); err == nil {
+			listeners[i] = pc
 		}
 		}
 	}
 	}
-
 	return listeners, nil
 	return listeners, nil
 }
 }

+ 37 - 0
vendor/src/github.com/coreos/go-systemd/activation/packetconns.go

@@ -0,0 +1,37 @@
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package activation
+
+import (
+	"net"
+)
+
+// PacketConns returns a slice containing a net.PacketConn for each matching socket type
+// passed to this process.
+//
+// The order of the file descriptors is preserved in the returned slice.
+// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
+// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn}
+func PacketConns(unsetEnv bool) ([]net.PacketConn, error) {
+	files := Files(unsetEnv)
+	conns := make([]net.PacketConn, len(files))
+
+	for i, f := range files {
+		if pc, err := net.FilePacketConn(f); err == nil {
+			conns[i] = pc
+		}
+	}
+	return conns, nil
+}

+ 109 - 50
vendor/src/github.com/coreos/go-systemd/dbus/dbus.go

@@ -1,23 +1,22 @@
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 // Integration with the systemd D-Bus API.  See http://www.freedesktop.org/wiki/Software/systemd/dbus/
 // Integration with the systemd D-Bus API.  See http://www.freedesktop.org/wiki/Software/systemd/dbus/
 package dbus
 package dbus
 
 
 import (
 import (
+	"fmt"
 	"os"
 	"os"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -26,24 +25,53 @@ import (
 	"github.com/godbus/dbus"
 	"github.com/godbus/dbus"
 )
 )
 
 
-const signalBuffer = 100
+const (
+	alpha        = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`
+	num          = `0123456789`
+	alphanum     = alpha + num
+	signalBuffer = 100
+)
 
 
-// ObjectPath creates a dbus.ObjectPath using the rules that systemd uses for
-// serializing special characters.
-func ObjectPath(path string) dbus.ObjectPath {
-	path = strings.Replace(path, ".", "_2e", -1)
-	path = strings.Replace(path, "-", "_2d", -1)
-	path = strings.Replace(path, "@", "_40", -1)
+// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped
+func needsEscape(i int, b byte) bool {
+	// Escape everything that is not a-z-A-Z-0-9
+	// Also escape 0-9 if it's the first character
+	return strings.IndexByte(alphanum, b) == -1 ||
+		(i == 0 && strings.IndexByte(num, b) != -1)
+}
 
 
-	return dbus.ObjectPath(path)
+// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the
+// rules that systemd uses for serializing special characters.
+func PathBusEscape(path string) string {
+	// Special case the empty string
+	if len(path) == 0 {
+		return "_"
+	}
+	n := []byte{}
+	for i := 0; i < len(path); i++ {
+		c := path[i]
+		if needsEscape(i, c) {
+			e := fmt.Sprintf("_%x", c)
+			n = append(n, []byte(e)...)
+		} else {
+			n = append(n, c)
+		}
+	}
+	return string(n)
 }
 }
 
 
-// Conn is a connection to systemds dbus endpoint.
+// Conn is a connection to systemd's dbus endpoint.
 type Conn struct {
 type Conn struct {
-	sysconn     *dbus.Conn
-	sysobj      *dbus.Object
+	// sysconn/sysobj are only used to call dbus methods
+	sysconn *dbus.Conn
+	sysobj  *dbus.Object
+
+	// sigconn/sigobj are only used to receive dbus signals
+	sigconn *dbus.Conn
+	sigobj  *dbus.Object
+
 	jobListener struct {
 	jobListener struct {
-		jobs map[dbus.ObjectPath]chan string
+		jobs map[dbus.ObjectPath]chan<- string
 		sync.Mutex
 		sync.Mutex
 	}
 	}
 	subscriber struct {
 	subscriber struct {
@@ -53,26 +81,61 @@ type Conn struct {
 		ignore      map[dbus.ObjectPath]int64
 		ignore      map[dbus.ObjectPath]int64
 		cleanIgnore int64
 		cleanIgnore int64
 	}
 	}
-	dispatch map[string]func(dbus.Signal)
 }
 }
 
 
-// New() establishes a connection to the system bus and authenticates.
+// New establishes a connection to the system bus and authenticates.
+// Callers should call Close() when done with the connection.
 func New() (*Conn, error) {
 func New() (*Conn, error) {
-	c := new(Conn)
+	return newConnection(dbus.SystemBusPrivate)
+}
+
+// NewUserConnection establishes a connection to the session bus and
+// authenticates. This can be used to connect to systemd user instances.
+// Callers should call Close() when done with the connection.
+func NewUserConnection() (*Conn, error) {
+	return newConnection(dbus.SessionBusPrivate)
+}
+
+// Close closes an established connection
+func (c *Conn) Close() {
+	c.sysconn.Close()
+	c.sigconn.Close()
+}
+
+func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) {
+	sysconn, err := dbusConnection(createBus)
+	if err != nil {
+		return nil, err
+	}
 
 
-	if err := c.initConnection(); err != nil {
+	sigconn, err := dbusConnection(createBus)
+	if err != nil {
+		sysconn.Close()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	c.initJobs()
+	c := &Conn{
+		sysconn: sysconn,
+		sysobj:  systemdObject(sysconn),
+		sigconn: sigconn,
+		sigobj:  systemdObject(sigconn),
+	}
+
+	c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
+	c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string)
+
+	// Setup the listeners on jobs so that we can get completions
+	c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
+		"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
+
+	c.dispatch()
 	return c, nil
 	return c, nil
 }
 }
 
 
-func (c *Conn) initConnection() error {
-	var err error
-	c.sysconn, err = dbus.SystemBusPrivate()
+func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
+	conn, err := createBus()
 	if err != nil {
 	if err != nil {
-		return err
+		return nil, err
 	}
 	}
 
 
 	// Only use EXTERNAL method, and hardcode the uid (not username)
 	// Only use EXTERNAL method, and hardcode the uid (not username)
@@ -80,25 +143,21 @@ func (c *Conn) initConnection() error {
 	// libc)
 	// libc)
 	methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
 	methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
 
 
-	err = c.sysconn.Auth(methods)
+	err = conn.Auth(methods)
 	if err != nil {
 	if err != nil {
-		c.sysconn.Close()
-		return err
+		conn.Close()
+		return nil, err
 	}
 	}
 
 
-	err = c.sysconn.Hello()
+	err = conn.Hello()
 	if err != nil {
 	if err != nil {
-		c.sysconn.Close()
-		return err
+		conn.Close()
+		return nil, err
 	}
 	}
 
 
-	c.sysobj = c.sysconn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
-
-	// Setup the listeners on jobs so that we can get completions
-	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
-		"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
-	c.initSubscription()
-	c.initDispatch()
+	return conn, nil
+}
 
 
-	return nil
+func systemdObject(conn *dbus.Conn) *dbus.Object {
+	return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
 }
 }

+ 69 - 55
vendor/src/github.com/coreos/go-systemd/dbus/methods.go

@@ -1,30 +1,27 @@
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 package dbus
 package dbus
 
 
 import (
 import (
 	"errors"
 	"errors"
+	"path"
+	"strconv"
+
 	"github.com/godbus/dbus"
 	"github.com/godbus/dbus"
 )
 )
 
 
-func (c *Conn) initJobs() {
-	c.jobListener.jobs = make(map[dbus.ObjectPath]chan string)
-}
-
 func (c *Conn) jobComplete(signal *dbus.Signal) {
 func (c *Conn) jobComplete(signal *dbus.Signal) {
 	var id uint32
 	var id uint32
 	var job dbus.ObjectPath
 	var job dbus.ObjectPath
@@ -40,29 +37,29 @@ func (c *Conn) jobComplete(signal *dbus.Signal) {
 	c.jobListener.Unlock()
 	c.jobListener.Unlock()
 }
 }
 
 
-func (c *Conn) startJob(job string, args ...interface{}) (<-chan string, error) {
-	c.jobListener.Lock()
-	defer c.jobListener.Unlock()
+func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) {
+	if ch != nil {
+		c.jobListener.Lock()
+		defer c.jobListener.Unlock()
+	}
 
 
-	ch := make(chan string, 1)
-	var path dbus.ObjectPath
-	err := c.sysobj.Call(job, 0, args...).Store(&path)
+	var p dbus.ObjectPath
+	err := c.sysobj.Call(job, 0, args...).Store(&p)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return 0, err
 	}
 	}
-	c.jobListener.jobs[path] = ch
-	return ch, nil
-}
 
 
-func (c *Conn) runJob(job string, args ...interface{}) (string, error) {
-	respCh, err := c.startJob(job, args...)
-	if err != nil {
-		return "", err
+	if ch != nil {
+		c.jobListener.jobs[p] = ch
 	}
 	}
-	return <-respCh, nil
+
+	// ignore error since 0 is fine if conversion fails
+	jobID, _ := strconv.Atoi(path.Base(string(p)))
+
+	return jobID, nil
 }
 }
 
 
-// StartUnit enqeues a start job and depending jobs, if any (unless otherwise
+// StartUnit enqueues a start job and depending jobs, if any (unless otherwise
 // specified by the mode string).
 // specified by the mode string).
 //
 //
 // Takes the unit to activate, plus a mode string. The mode needs to be one of
 // Takes the unit to activate, plus a mode string. The mode needs to be one of
@@ -77,50 +74,58 @@ func (c *Conn) runJob(job string, args ...interface{}) (string, error) {
 // requirement dependencies. It is not recommended to make use of the latter
 // requirement dependencies. It is not recommended to make use of the latter
 // two options.
 // two options.
 //
 //
-// Result string: one of done, canceled, timeout, failed, dependency, skipped.
+// If the provided channel is non-nil, a result string will be sent to it upon
+// job completion: one of done, canceled, timeout, failed, dependency, skipped.
 // done indicates successful execution of a job. canceled indicates that a job
 // done indicates successful execution of a job. canceled indicates that a job
 // has been canceled  before it finished execution. timeout indicates that the
 // has been canceled  before it finished execution. timeout indicates that the
 // job timeout was reached. failed indicates that the job failed. dependency
 // job timeout was reached. failed indicates that the job failed. dependency
 // indicates that a job this job has been depending on failed and the job hence
 // indicates that a job this job has been depending on failed and the job hence
 // has been removed too. skipped indicates that a job was skipped because it
 // has been removed too. skipped indicates that a job was skipped because it
 // didn't apply to the units current state.
 // didn't apply to the units current state.
-func (c *Conn) StartUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.StartUnit", name, mode)
+//
+// If no error occurs, the ID of the underlying systemd job will be returned. There
+// does exist the possibility for no error to be returned, but for the returned job
+// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint
+// should not be considered authoritative.
+//
+// If an error does occur, it will be returned to the user alongside a job ID of 0.
+func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode)
 }
 }
 
 
 // StopUnit is similar to StartUnit but stops the specified unit rather
 // StopUnit is similar to StartUnit but stops the specified unit rather
 // than starting it.
 // than starting it.
-func (c *Conn) StopUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.StopUnit", name, mode)
+func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode)
 }
 }
 
 
 // ReloadUnit reloads a unit.  Reloading is done only if the unit is already running and fails otherwise.
 // ReloadUnit reloads a unit.  Reloading is done only if the unit is already running and fails otherwise.
-func (c *Conn) ReloadUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
+func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
 }
 }
 
 
 // RestartUnit restarts a service.  If a service is restarted that isn't
 // RestartUnit restarts a service.  If a service is restarted that isn't
 // running it will be started.
 // running it will be started.
-func (c *Conn) RestartUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
+func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
 }
 }
 
 
 // TryRestartUnit is like RestartUnit, except that a service that isn't running
 // TryRestartUnit is like RestartUnit, except that a service that isn't running
 // is not affected by the restart.
 // is not affected by the restart.
-func (c *Conn) TryRestartUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
+func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
 }
 }
 
 
 // ReloadOrRestart attempts a reload if the unit supports it and use a restart
 // ReloadOrRestart attempts a reload if the unit supports it and use a restart
 // otherwise.
 // otherwise.
-func (c *Conn) ReloadOrRestartUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
+func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
 }
 }
 
 
 // ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
 // ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
 // flavored restart otherwise.
 // flavored restart otherwise.
-func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
+func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
 }
 }
 
 
 // StartTransientUnit() may be used to create and start a transient unit, which
 // StartTransientUnit() may be used to create and start a transient unit, which
@@ -128,8 +133,8 @@ func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error)
 // system is rebooted. name is the unit name including suffix, and must be
 // system is rebooted. name is the unit name including suffix, and must be
 // unique. mode is the same as in StartUnit(), properties contains properties
 // unique. mode is the same as in StartUnit(), properties contains properties
 // of the unit.
 // of the unit.
-func (c *Conn) StartTransientUnit(name string, mode string, properties ...Property) (string, error) {
-	return c.runJob("org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
+func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
+	return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
 }
 }
 
 
 // KillUnit takes the unit name and a UNIX signal number to send.  All of the unit's
 // KillUnit takes the unit name and a UNIX signal number to send.  All of the unit's
@@ -138,12 +143,17 @@ func (c *Conn) KillUnit(name string, signal int32) {
 	c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store()
 	c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store()
 }
 }
 
 
+// ResetFailedUnit resets the "failed" state of a specific unit.
+func (c *Conn) ResetFailedUnit(name string) error {
+	return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store()
+}
+
 // getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface
 // getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface
 func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) {
 func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) {
 	var err error
 	var err error
 	var props map[string]dbus.Variant
 	var props map[string]dbus.Variant
 
 
-	path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit)
+	path := unitPath(unit)
 	if !path.IsValid() {
 	if !path.IsValid() {
 		return nil, errors.New("invalid unit name: " + unit)
 		return nil, errors.New("invalid unit name: " + unit)
 	}
 	}
@@ -171,7 +181,7 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin
 	var err error
 	var err error
 	var prop dbus.Variant
 	var prop dbus.Variant
 
 
-	path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit)
+	path := unitPath(unit)
 	if !path.IsValid() {
 	if !path.IsValid() {
 		return nil, errors.New("invalid unit name: " + unit)
 		return nil, errors.New("invalid unit name: " + unit)
 	}
 	}
@@ -208,7 +218,7 @@ func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Proper
 }
 }
 
 
 func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
 func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
-	return c.getProperty(unit, "org.freedesktop.systemd1." + unitType, propertyName)
+	return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName)
 }
 }
 
 
 // ListUnits returns an array with all currently loaded units. Note that
 // ListUnits returns an array with all currently loaded units. Note that
@@ -394,3 +404,7 @@ type DisableUnitFileChange struct {
 func (c *Conn) Reload() error {
 func (c *Conn) Reload() error {
 	return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
 	return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
 }
 }
+
+func unitPath(name string) dbus.ObjectPath {
+	return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name))
+}

+ 13 - 15
vendor/src/github.com/coreos/go-systemd/dbus/properties.go

@@ -1,18 +1,16 @@
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 package dbus
 package dbus
 
 

+ 20 - 6
vendor/src/github.com/coreos/go-systemd/dbus/set.go

@@ -1,3 +1,17 @@
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 package dbus
 package dbus
 
 
 type set struct {
 type set struct {
@@ -17,17 +31,17 @@ func (s *set) Contains(value string) (exists bool) {
 	return
 	return
 }
 }
 
 
-func (s *set) Length() (int) {
+func (s *set) Length() int {
 	return len(s.data)
 	return len(s.data)
 }
 }
 
 
 func (s *set) Values() (values []string) {
 func (s *set) Values() (values []string) {
-	 for val, _ := range s.data {
+	for val, _ := range s.data {
 		values = append(values, val)
 		values = append(values, val)
-	 }
-	 return
+	}
+	return
 }
 }
 
 
-func newSet() (*set) {
-	return &set{make(map[string] bool)}
+func newSet() *set {
+	return &set{make(map[string]bool)}
 }
 }

+ 37 - 38
vendor/src/github.com/coreos/go-systemd/dbus/subscription.go

@@ -1,18 +1,16 @@
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 package dbus
 package dbus
 
 
@@ -33,12 +31,12 @@ const (
 // systemd will automatically stop sending signals so there is no need to
 // systemd will automatically stop sending signals so there is no need to
 // explicitly call Unsubscribe().
 // explicitly call Unsubscribe().
 func (c *Conn) Subscribe() error {
 func (c *Conn) Subscribe() error {
-	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
+	c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 		"type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'")
 		"type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'")
-	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
+	c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 		"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
 		"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
 
 
-	err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
+	err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -48,7 +46,7 @@ func (c *Conn) Subscribe() error {
 
 
 // Unsubscribe this connection from systemd dbus events.
 // Unsubscribe this connection from systemd dbus events.
 func (c *Conn) Unsubscribe() error {
 func (c *Conn) Unsubscribe() error {
-	err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
+	err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -56,14 +54,10 @@ func (c *Conn) Unsubscribe() error {
 	return nil
 	return nil
 }
 }
 
 
-func (c *Conn) initSubscription() {
-	c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
-}
-
-func (c *Conn) initDispatch() {
+func (c *Conn) dispatch() {
 	ch := make(chan *dbus.Signal, signalBuffer)
 	ch := make(chan *dbus.Signal, signalBuffer)
 
 
-	c.sysconn.Signal(ch)
+	c.sigconn.Signal(ch)
 
 
 	go func() {
 	go func() {
 		for {
 		for {
@@ -72,24 +66,32 @@ func (c *Conn) initDispatch() {
 				return
 				return
 			}
 			}
 
 
-			switch signal.Name {
-			case "org.freedesktop.systemd1.Manager.JobRemoved":
+			if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" {
 				c.jobComplete(signal)
 				c.jobComplete(signal)
+			}
+
+			if c.subscriber.updateCh == nil {
+				continue
+			}
 
 
+			var unitPath dbus.ObjectPath
+			switch signal.Name {
+			case "org.freedesktop.systemd1.Manager.JobRemoved":
 				unitName := signal.Body[2].(string)
 				unitName := signal.Body[2].(string)
-				var unitPath dbus.ObjectPath
 				c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
 				c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
-				if unitPath != dbus.ObjectPath("") {
-					c.sendSubStateUpdate(unitPath)
-				}
 			case "org.freedesktop.systemd1.Manager.UnitNew":
 			case "org.freedesktop.systemd1.Manager.UnitNew":
-				c.sendSubStateUpdate(signal.Body[1].(dbus.ObjectPath))
+				unitPath = signal.Body[1].(dbus.ObjectPath)
 			case "org.freedesktop.DBus.Properties.PropertiesChanged":
 			case "org.freedesktop.DBus.Properties.PropertiesChanged":
 				if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
 				if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
-					// we only care about SubState updates, which are a Unit property
-					c.sendSubStateUpdate(signal.Path)
+					unitPath = signal.Path
 				}
 				}
 			}
 			}
+
+			if unitPath == dbus.ObjectPath("") {
+				continue
+			}
+
+			c.sendSubStateUpdate(unitPath)
 		}
 		}
 	}()
 	}()
 }
 }
@@ -103,7 +105,7 @@ func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitSt
 // SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
 // SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
 // size of the channels, the comparison function for detecting changes and a filter
 // size of the channels, the comparison function for detecting changes and a filter
 // function for cutting down on the noise that your channel receives.
 // function for cutting down on the noise that your channel receives.
-func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func (string) bool) (<-chan map[string]*UnitStatus, <-chan error) {
+func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) {
 	old := make(map[string]*UnitStatus)
 	old := make(map[string]*UnitStatus)
 	statusChan := make(chan map[string]*UnitStatus, buffer)
 	statusChan := make(chan map[string]*UnitStatus, buffer)
 	errChan := make(chan error, buffer)
 	errChan := make(chan error, buffer)
@@ -176,9 +178,6 @@ func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan
 func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
 func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
 	c.subscriber.Lock()
 	c.subscriber.Lock()
 	defer c.subscriber.Unlock()
 	defer c.subscriber.Unlock()
-	if c.subscriber.updateCh == nil {
-		return
-	}
 
 
 	if c.shouldIgnore(path) {
 	if c.shouldIgnore(path) {
 		return
 		return

+ 28 - 3
vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go

@@ -1,3 +1,17 @@
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 package dbus
 package dbus
 
 
 import (
 import (
@@ -11,7 +25,6 @@ type SubscriptionSet struct {
 	conn *Conn
 	conn *Conn
 }
 }
 
 
-
 func (s *SubscriptionSet) filter(unit string) bool {
 func (s *SubscriptionSet) filter(unit string) bool {
 	return !s.Contains(unit)
 	return !s.Contains(unit)
 }
 }
@@ -21,12 +34,24 @@ func (s *SubscriptionSet) filter(unit string) bool {
 func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) {
 func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) {
 	// TODO: Make fully evented by using systemd 209 with properties changed values
 	// TODO: Make fully evented by using systemd 209 with properties changed values
 	return s.conn.SubscribeUnitsCustom(time.Second, 0,
 	return s.conn.SubscribeUnitsCustom(time.Second, 0,
-		func(u1, u2 *UnitStatus) bool { return *u1 != *u2 },
+		mismatchUnitStatus,
 		func(unit string) bool { return s.filter(unit) },
 		func(unit string) bool { return s.filter(unit) },
 	)
 	)
 }
 }
 
 
 // NewSubscriptionSet returns a new subscription set.
 // NewSubscriptionSet returns a new subscription set.
-func (conn *Conn) NewSubscriptionSet() (*SubscriptionSet) {
+func (conn *Conn) NewSubscriptionSet() *SubscriptionSet {
 	return &SubscriptionSet{newSet(), conn}
 	return &SubscriptionSet{newSet(), conn}
 }
 }
+
+// mismatchUnitStatus returns true if the provided UnitStatus objects
+// are not equivalent. false is returned if the objects are equivalent.
+// Only the Name, Description and state-related fields are used in
+// the comparison.
+func mismatchUnitStatus(u1, u2 *UnitStatus) bool {
+	return u1.Name != u2.Name ||
+		u1.Description != u2.Description ||
+		u1.LoadState != u2.LoadState ||
+		u1.ActiveState != u2.ActiveState ||
+		u1.SubState != u2.SubState
+}

+ 13 - 15
vendor/src/github.com/coreos/go-systemd/journal/send.go

@@ -1,18 +1,16 @@
-/*
-Copyright 2013 CoreOS Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 
 // Package journal provides write bindings to the systemd journal
 // Package journal provides write bindings to the systemd journal
 package journal
 package journal

+ 33 - 0
vendor/src/github.com/coreos/go-systemd/util/util.go

@@ -0,0 +1,33 @@
+// Copyright 2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package util contains utility functions related to systemd that applications
+// can use to check things like whether systemd is running.
+package util
+
+import (
+	"os"
+)
+
+// IsRunningSystemd checks whether the host was booted with systemd as its init
+// system. This functions similar to systemd's `sd_booted(3)`: internally, it
+// checks whether /run/systemd/system/ exists and is a directory.
+// http://www.freedesktop.org/software/systemd/man/sd_booted.html
+func IsRunningSystemd() bool {
+	fi, err := os.Lstat("/run/systemd/system")
+	if err != nil {
+		return false
+	}
+	return fi.IsDir()
+}

+ 2 - 2
vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go

@@ -256,7 +256,7 @@ func (raw *data) path(subsystem string) (string, error) {
 
 
 	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
 	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
 	if filepath.IsAbs(raw.cgroup) {
 	if filepath.IsAbs(raw.cgroup) {
-		return filepath.Join(raw.root, subsystem, raw.cgroup), nil
+		return filepath.Join(raw.root, filepath.Base(mnt), raw.cgroup), nil
 	}
 	}
 
 
 	parent, err := raw.parent(subsystem, mnt, src)
 	parent, err := raw.parent(subsystem, mnt, src)
@@ -272,7 +272,7 @@ func (raw *data) join(subsystem string) (string, error) {
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
-	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+	if err := os.MkdirAll(path, 0755); err != nil {
 		return "", err
 		return "", err
 	}
 	}
 	if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil {
 	if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil {

+ 1 - 1
vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go

@@ -95,7 +95,7 @@ func (s *CpusetGroup) ensureParent(current, root string) error {
 	if err := s.ensureParent(parent, root); err != nil {
 	if err := s.ensureParent(parent, root); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := os.MkdirAll(current, 0755); err != nil && !os.IsExist(err) {
+	if err := os.MkdirAll(current, 0755); err != nil {
 		return err
 		return err
 	}
 	}
 	return s.copyIfNeeded(current, parent)
 	return s.copyIfNeeded(current, parent)

+ 1 - 1
vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go

@@ -25,7 +25,7 @@ func (s *MemoryGroup) Apply(d *data) error {
 		}
 		}
 		return err
 		return err
 	}
 	}
-	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+	if err := os.MkdirAll(path, 0755); err != nil {
 		return err
 		return err
 	}
 	}
 	if err := s.Set(path, d.c); err != nil {
 	if err := s.Set(path, d.c); err != nil {

+ 18 - 18
vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go

@@ -12,7 +12,8 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
-	systemd "github.com/coreos/go-systemd/dbus"
+	systemdDbus "github.com/coreos/go-systemd/dbus"
+	systemdUtil "github.com/coreos/go-systemd/util"
 	"github.com/godbus/dbus"
 	"github.com/godbus/dbus"
 	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/cgroups/fs"
 	"github.com/opencontainers/runc/libcontainer/cgroups/fs"
@@ -52,21 +53,20 @@ const (
 
 
 var (
 var (
 	connLock                        sync.Mutex
 	connLock                        sync.Mutex
-	theConn                         *systemd.Conn
+	theConn                         *systemdDbus.Conn
 	hasStartTransientUnit           bool
 	hasStartTransientUnit           bool
 	hasTransientDefaultDependencies bool
 	hasTransientDefaultDependencies bool
 )
 )
 
 
-func newProp(name string, units interface{}) systemd.Property {
-	return systemd.Property{
+func newProp(name string, units interface{}) systemdDbus.Property {
+	return systemdDbus.Property{
 		Name:  name,
 		Name:  name,
 		Value: dbus.MakeVariant(units),
 		Value: dbus.MakeVariant(units),
 	}
 	}
 }
 }
 
 
 func UseSystemd() bool {
 func UseSystemd() bool {
-	s, err := os.Stat("/run/systemd/system")
-	if err != nil || !s.IsDir() {
+	if !systemdUtil.IsRunningSystemd() {
 		return false
 		return false
 	}
 	}
 
 
@@ -75,7 +75,7 @@ func UseSystemd() bool {
 
 
 	if theConn == nil {
 	if theConn == nil {
 		var err error
 		var err error
-		theConn, err = systemd.New()
+		theConn, err = systemdDbus.New()
 		if err != nil {
 		if err != nil {
 			return false
 			return false
 		}
 		}
@@ -84,7 +84,7 @@ func UseSystemd() bool {
 		hasStartTransientUnit = true
 		hasStartTransientUnit = true
 
 
 		// But if we get UnknownMethod error we don't
 		// But if we get UnknownMethod error we don't
-		if _, err := theConn.StartTransientUnit("test.scope", "invalid"); err != nil {
+		if _, err := theConn.StartTransientUnit("test.scope", "invalid", nil, nil); err != nil {
 			if dbusError, ok := err.(dbus.Error); ok {
 			if dbusError, ok := err.(dbus.Error); ok {
 				if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
 				if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
 					hasStartTransientUnit = false
 					hasStartTransientUnit = false
@@ -99,7 +99,7 @@ func UseSystemd() bool {
 		scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
 		scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
 		testScopeExists := true
 		testScopeExists := true
 		for i := 0; i <= testScopeWait; i++ {
 		for i := 0; i <= testScopeWait; i++ {
-			if _, err := theConn.StopUnit(scope, "replace"); err != nil {
+			if _, err := theConn.StopUnit(scope, "replace", nil); err != nil {
 				if dbusError, ok := err.(dbus.Error); ok {
 				if dbusError, ok := err.(dbus.Error); ok {
 					if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
 					if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
 						testScopeExists = false
 						testScopeExists = false
@@ -118,7 +118,7 @@ func UseSystemd() bool {
 		// Assume StartTransientUnit on a scope allows DefaultDependencies
 		// Assume StartTransientUnit on a scope allows DefaultDependencies
 		hasTransientDefaultDependencies = true
 		hasTransientDefaultDependencies = true
 		ddf := newProp("DefaultDependencies", false)
 		ddf := newProp("DefaultDependencies", false)
-		if _, err := theConn.StartTransientUnit(scope, "replace", ddf); err != nil {
+		if _, err := theConn.StartTransientUnit(scope, "replace", []systemdDbus.Property{ddf}, nil); err != nil {
 			if dbusError, ok := err.(dbus.Error); ok {
 			if dbusError, ok := err.(dbus.Error); ok {
 				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
 				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
 					hasTransientDefaultDependencies = false
 					hasTransientDefaultDependencies = false
@@ -127,7 +127,7 @@ func UseSystemd() bool {
 		}
 		}
 
 
 		// Not critical because of the stop unit logic above.
 		// Not critical because of the stop unit logic above.
-		theConn.StopUnit(scope, "replace")
+		theConn.StopUnit(scope, "replace", nil)
 	}
 	}
 	return hasStartTransientUnit
 	return hasStartTransientUnit
 }
 }
@@ -147,7 +147,7 @@ func (m *Manager) Apply(pid int) error {
 		c          = m.Cgroups
 		c          = m.Cgroups
 		unitName   = getUnitName(c)
 		unitName   = getUnitName(c)
 		slice      = "system.slice"
 		slice      = "system.slice"
-		properties []systemd.Property
+		properties []systemdDbus.Property
 	)
 	)
 
 
 	if c.Slice != "" {
 	if c.Slice != "" {
@@ -155,8 +155,8 @@ func (m *Manager) Apply(pid int) error {
 	}
 	}
 
 
 	properties = append(properties,
 	properties = append(properties,
-		systemd.PropSlice(slice),
-		systemd.PropDescription("docker container "+c.Name),
+		systemdDbus.PropSlice(slice),
+		systemdDbus.PropDescription("docker container "+c.Name),
 		newProp("PIDs", []uint32{uint32(pid)}),
 		newProp("PIDs", []uint32{uint32(pid)}),
 	)
 	)
 
 
@@ -198,7 +198,7 @@ func (m *Manager) Apply(pid int) error {
 		}
 		}
 	}
 	}
 
 
-	if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
+	if _, err := theConn.StartTransientUnit(unitName, "replace", properties, nil); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -269,7 +269,7 @@ func (m *Manager) Apply(pid int) error {
 func (m *Manager) Destroy() error {
 func (m *Manager) Destroy() error {
 	m.mu.Lock()
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	defer m.mu.Unlock()
-	theConn.StopUnit(getUnitName(m.Cgroups), "replace")
+	theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil)
 	if err := cgroups.RemovePaths(m.Paths); err != nil {
 	if err := cgroups.RemovePaths(m.Paths); err != nil {
 		return err
 		return err
 	}
 	}
@@ -298,7 +298,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
-	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+	if err := os.MkdirAll(path, 0755); err != nil {
 		return "", err
 		return "", err
 	}
 	}
 	if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
 	if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
@@ -478,7 +478,7 @@ func setKernelMemory(c *configs.Cgroup) error {
 		return err
 		return err
 	}
 	}
 
 
-	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+	if err := os.MkdirAll(path, 0755); err != nil {
 		return err
 		return err
 	}
 	}
 
 

+ 4 - 0
vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go

@@ -25,6 +25,8 @@ func FindCgroupMountpoint(subsystem string) (string, error) {
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
+	defer f.Close()
+
 	scanner := bufio.NewScanner(f)
 	scanner := bufio.NewScanner(f)
 	for scanner.Scan() {
 	for scanner.Scan() {
 		txt := scanner.Text()
 		txt := scanner.Text()
@@ -47,6 +49,8 @@ func FindCgroupMountpointAndSource(subsystem string) (string, string, error) {
 	if err != nil {
 	if err != nil {
 		return "", "", err
 		return "", "", err
 	}
 	}
+	defer f.Close()
+
 	scanner := bufio.NewScanner(f)
 	scanner := bufio.NewScanner(f)
 	for scanner.Scan() {
 	for scanner.Scan() {
 		txt := scanner.Text()
 		txt := scanner.Text()

+ 10 - 0
vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go

@@ -0,0 +1,10 @@
+// +build linux,!go1.5
+
+package libcontainer
+
+import "syscall"
+
+// GidMappingsEnableSetgroups was added in Go 1.5, so do nothing when building
+// with earlier versions
+func enableSetgroups(sys *syscall.SysProcAttr) {
+}

+ 8 - 0
vendor/src/github.com/opencontainers/runc/libcontainer/container.go

@@ -5,6 +5,8 @@
 package libcontainer
 package libcontainer
 
 
 import (
 import (
+	"os"
+
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/configs"
 )
 )
 
 
@@ -159,4 +161,10 @@ type Container interface {
 	// errors:
 	// errors:
 	// Systemerror - System error.
 	// Systemerror - System error.
 	NotifyOOM() (<-chan struct{}, error)
 	NotifyOOM() (<-chan struct{}, error)
+
+	// Signal sends the provided signal code to the container's initial process.
+	//
+	// errors:
+	// Systemerror - System error.
+	Signal(s os.Signal) error
 }
 }

+ 63 - 23
vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go

@@ -118,6 +118,13 @@ func (c *linuxContainer) Start(process *Process) error {
 	return nil
 	return nil
 }
 }
 
 
+func (c *linuxContainer) Signal(s os.Signal) error {
+	if err := c.initProcess.signal(s); err != nil {
+		return newSystemError(err)
+	}
+	return nil
+}
+
 func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
 func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
 	parentPipe, childPipe, err := newPipe()
 	parentPipe, childPipe, err := newPipe()
 	if err != nil {
 	if err != nil {
@@ -164,6 +171,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c
 			// user mappings are not supported
 			// user mappings are not supported
 			return nil, err
 			return nil, err
 		}
 		}
+		enableSetgroups(cmd.SysProcAttr)
 		// Default to root user when user namespaces are enabled.
 		// Default to root user when user namespaces are enabled.
 		if cmd.SysProcAttr.Credential == nil {
 		if cmd.SysProcAttr.Credential == nil {
 			cmd.SysProcAttr.Credential = &syscall.Credential{}
 			cmd.SysProcAttr.Credential = &syscall.Credential{}
@@ -273,7 +281,7 @@ func (c *linuxContainer) checkCriuVersion() error {
 
 
 	out, err := exec.Command(c.criuPath, "-V").Output()
 	out, err := exec.Command(c.criuPath, "-V").Output()
 	if err != nil {
 	if err != nil {
-		return err
+		return fmt.Errorf("Unable to execute CRIU command: %s", c.criuPath)
 	}
 	}
 
 
 	n, err := fmt.Sscanf(string(out), "Version: %d.%d.%d\n", &x, &y, &z) // 1.5.2
 	n, err := fmt.Sscanf(string(out), "Version: %d.%d.%d\n", &x, &y, &z) // 1.5.2
@@ -293,6 +301,19 @@ func (c *linuxContainer) checkCriuVersion() error {
 
 
 const descriptors_filename = "descriptors.json"
 const descriptors_filename = "descriptors.json"
 
 
+func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) {
+	mountDest := m.Destination
+	if strings.HasPrefix(mountDest, c.config.Rootfs) {
+		mountDest = mountDest[len(c.config.Rootfs):]
+	}
+
+	extMnt := &criurpc.ExtMountMap{
+		Key: proto.String(mountDest),
+		Val: proto.String(mountDest),
+	}
+	req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
+}
+
 func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
 func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
 	c.m.Lock()
 	c.m.Lock()
 	defer c.m.Unlock()
 	defer c.m.Unlock()
@@ -356,22 +377,25 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
 	}
 	}
 
 
 	t := criurpc.CriuReqType_DUMP
 	t := criurpc.CriuReqType_DUMP
-	req := criurpc.CriuReq{
+	req := &criurpc.CriuReq{
 		Type: &t,
 		Type: &t,
 		Opts: &rpcOpts,
 		Opts: &rpcOpts,
 	}
 	}
 
 
 	for _, m := range c.config.Mounts {
 	for _, m := range c.config.Mounts {
-		if m.Device == "bind" {
-			mountDest := m.Destination
-			if strings.HasPrefix(mountDest, c.config.Rootfs) {
-				mountDest = mountDest[len(c.config.Rootfs):]
+		switch m.Device {
+		case "bind":
+			c.addCriuDumpMount(req, m)
+			break
+		case "cgroup":
+			binds, err := getCgroupMounts(m)
+			if err != nil {
+				return err
 			}
 			}
-
-			extMnt := new(criurpc.ExtMountMap)
-			extMnt.Key = proto.String(mountDest)
-			extMnt.Val = proto.String(mountDest)
-			req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
+			for _, b := range binds {
+				c.addCriuDumpMount(req, b)
+			}
+			break
 		}
 		}
 	}
 	}
 
 
@@ -387,13 +411,26 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
 		return err
 		return err
 	}
 	}
 
 
-	err = c.criuSwrk(nil, &req, criuOpts)
+	err = c.criuSwrk(nil, req, criuOpts)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
+func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) {
+	mountDest := m.Destination
+	if strings.HasPrefix(mountDest, c.config.Rootfs) {
+		mountDest = mountDest[len(c.config.Rootfs):]
+	}
+
+	extMnt := &criurpc.ExtMountMap{
+		Key: proto.String(mountDest),
+		Val: proto.String(m.Source),
+	}
+	req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
+}
+
 func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
 func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
 	c.m.Lock()
 	c.m.Lock()
 	defer c.m.Unlock()
 	defer c.m.Unlock()
@@ -449,7 +486,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
 	defer syscall.Unmount(root, syscall.MNT_DETACH)
 	defer syscall.Unmount(root, syscall.MNT_DETACH)
 
 
 	t := criurpc.CriuReqType_RESTORE
 	t := criurpc.CriuReqType_RESTORE
-	req := criurpc.CriuReq{
+	req := &criurpc.CriuReq{
 		Type: &t,
 		Type: &t,
 		Opts: &criurpc.CriuOpts{
 		Opts: &criurpc.CriuOpts{
 			ImagesDirFd:    proto.Int32(int32(imageDir.Fd())),
 			ImagesDirFd:    proto.Int32(int32(imageDir.Fd())),
@@ -468,16 +505,19 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
 		},
 		},
 	}
 	}
 	for _, m := range c.config.Mounts {
 	for _, m := range c.config.Mounts {
-		if m.Device == "bind" {
-			mountDest := m.Destination
-			if strings.HasPrefix(mountDest, c.config.Rootfs) {
-				mountDest = mountDest[len(c.config.Rootfs):]
+		switch m.Device {
+		case "bind":
+			c.addCriuRestoreMount(req, m)
+			break
+		case "cgroup":
+			binds, err := getCgroupMounts(m)
+			if err != nil {
+				return err
 			}
 			}
-
-			extMnt := new(criurpc.ExtMountMap)
-			extMnt.Key = proto.String(mountDest)
-			extMnt.Val = proto.String(m.Source)
-			req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
+			for _, b := range binds {
+				c.addCriuRestoreMount(req, b)
+			}
+			break
 		}
 		}
 	}
 	}
 	for _, iface := range c.config.Networks {
 	for _, iface := range c.config.Networks {
@@ -515,7 +555,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
 		}
 		}
 	}
 	}
 
 
-	err = c.criuSwrk(process, &req, criuOpts)
+	err = c.criuSwrk(process, req, criuOpts)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 1 - 1
vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go

@@ -46,7 +46,7 @@ func InitArgs(args ...string) func(*LinuxFactory) error {
 			}
 			}
 			name = abs
 			name = abs
 		}
 		}
-		l.InitPath = name
+		l.InitPath = "/proc/self/exe"
 		l.InitArgs = append([]string{name}, args[1:]...)
 		l.InitArgs = append([]string{name}, args[1:]...)
 		return nil
 		return nil
 	}
 	}

+ 1 - 1
vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go

@@ -34,7 +34,7 @@ type pid struct {
 type network struct {
 type network struct {
 	configs.Network
 	configs.Network
 
 
-	// TempVethPeerName is a unique tempory veth peer name that was placed into
+	// TempVethPeerName is a unique temporary veth peer name that was placed into
 	// the container's namespace.
 	// the container's namespace.
 	TempVethPeerName string `json:"temp_veth_peer_name"`
 	TempVethPeerName string `json:"temp_veth_peer_name"`
 }
 }

+ 5 - 1
vendor/src/github.com/opencontainers/runc/libcontainer/restored_process.go

@@ -106,7 +106,11 @@ func (p *nonChildProcess) startTime() (string, error) {
 }
 }
 
 
 func (p *nonChildProcess) signal(s os.Signal) error {
 func (p *nonChildProcess) signal(s os.Signal) error {
-	return newGenericError(fmt.Errorf("restored process cannot be signaled"), SystemError)
+	proc, err := os.FindProcess(p.processPid)
+	if err != nil {
+		return err
+	}
+	return proc.Signal(s)
 }
 }
 
 
 func (p *nonChildProcess) externalDescriptors() []string {
 func (p *nonChildProcess) externalDescriptors() []string {

+ 69 - 20
vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go

@@ -98,12 +98,12 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
 
 
 	switch m.Device {
 	switch m.Device {
 	case "proc", "sysfs":
 	case "proc", "sysfs":
-		if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
+		if err := os.MkdirAll(dest, 0755); err != nil {
 			return err
 			return err
 		}
 		}
 		return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
 		return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
 	case "mqueue":
 	case "mqueue":
-		if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
+		if err := os.MkdirAll(dest, 0755); err != nil {
 			return err
 			return err
 		}
 		}
 		if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), ""); err != nil {
 		if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), ""); err != nil {
@@ -113,7 +113,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
 	case "tmpfs":
 	case "tmpfs":
 		stat, err := os.Stat(dest)
 		stat, err := os.Stat(dest)
 		if err != nil {
 		if err != nil {
-			if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
+			if err := os.MkdirAll(dest, 0755); err != nil {
 				return err
 				return err
 			}
 			}
 		}
 		}
@@ -127,7 +127,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
 		}
 		}
 		return nil
 		return nil
 	case "devpts":
 	case "devpts":
-		if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
+		if err := os.MkdirAll(dest, 0755); err != nil {
 			return err
 			return err
 		}
 		}
 		return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data)
 		return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data)
@@ -170,32 +170,23 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
 			}
 			}
 		}
 		}
 	case "cgroup":
 	case "cgroup":
-		mounts, err := cgroups.GetCgroupMounts()
+		binds, err := getCgroupMounts(m)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		var binds []*configs.Mount
-		for _, mm := range mounts {
-			dir, err := mm.GetThisCgroupDir()
-			if err != nil {
-				return err
-			}
-			relDir, err := filepath.Rel(mm.Root, dir)
-			if err != nil {
-				return err
+		var merged []string
+		for _, b := range binds {
+			ss := filepath.Base(b.Destination)
+			if strings.Contains(ss, ",") {
+				merged = append(merged, ss)
 			}
 			}
-			binds = append(binds, &configs.Mount{
-				Device:      "bind",
-				Source:      filepath.Join(mm.Mountpoint, relDir),
-				Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
-				Flags:       syscall.MS_BIND | syscall.MS_REC | m.Flags,
-			})
 		}
 		}
 		tmpfs := &configs.Mount{
 		tmpfs := &configs.Mount{
 			Source:      "tmpfs",
 			Source:      "tmpfs",
 			Device:      "tmpfs",
 			Device:      "tmpfs",
 			Destination: m.Destination,
 			Destination: m.Destination,
 			Flags:       defaultMountFlags,
 			Flags:       defaultMountFlags,
+			Data:        "mode=755",
 		}
 		}
 		if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
 		if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
 			return err
 			return err
@@ -205,12 +196,70 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
 				return err
 				return err
 			}
 			}
 		}
 		}
+		// create symlinks for merged cgroups
+		cwd, err := os.Getwd()
+		if err != nil {
+			return err
+		}
+		if err := os.Chdir(filepath.Join(rootfs, m.Destination)); err != nil {
+			return err
+		}
+		for _, mc := range merged {
+			for _, ss := range strings.Split(mc, ",") {
+				if err := os.Symlink(mc, ss); err != nil {
+					// if cgroup already exists, then okay(it could have been created before)
+					if os.IsExist(err) {
+						continue
+					}
+					os.Chdir(cwd)
+					return err
+				}
+			}
+		}
+		if err := os.Chdir(cwd); err != nil {
+			return err
+		}
+		if m.Flags&syscall.MS_RDONLY != 0 {
+			// remount cgroup root as readonly
+			rootfsCgroup := filepath.Join(rootfs, m.Destination)
+			if err := syscall.Mount("", rootfsCgroup, "", defaultMountFlags|syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil {
+				return err
+			}
+		}
 	default:
 	default:
 		return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
 		return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
+func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
+	mounts, err := cgroups.GetCgroupMounts()
+	if err != nil {
+		return nil, err
+	}
+
+	var binds []*configs.Mount
+
+	for _, mm := range mounts {
+		dir, err := mm.GetThisCgroupDir()
+		if err != nil {
+			return nil, err
+		}
+		relDir, err := filepath.Rel(mm.Root, dir)
+		if err != nil {
+			return nil, err
+		}
+		binds = append(binds, &configs.Mount{
+			Device:      "bind",
+			Source:      filepath.Join(mm.Mountpoint, relDir),
+			Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
+			Flags:       syscall.MS_BIND | syscall.MS_REC | m.Flags,
+		})
+	}
+
+	return binds, nil
+}
+
 // checkMountDestination checks to ensure that the mount destination is not over the
 // checkMountDestination checks to ensure that the mount destination is not over the
 // top of /proc or /sys.
 // top of /proc or /sys.
 // dest is required to be an abs path and have any symlinks resolved before calling this function.
 // dest is required to be an abs path and have any symlinks resolved before calling this function.

+ 11 - 0
vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go

@@ -0,0 +1,11 @@
+// +build linux,go1.5
+
+package libcontainer
+
+import "syscall"
+
+// Set the GidMappingsEnableSetgroups member to true, so the process's
+// setgroups proc entry wont be set to 'deny' if GidMappings are set
+func enableSetgroups(sys *syscall.SysProcAttr) {
+	sys.GidMappingsEnableSetgroups = true
+}

+ 5 - 1
vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go

@@ -9,13 +9,17 @@ func Capture(userSkip int) Stacktrace {
 	var (
 	var (
 		skip   = userSkip + 1 // add one for our own function
 		skip   = userSkip + 1 // add one for our own function
 		frames []Frame
 		frames []Frame
+		prevPc uintptr = 0
 	)
 	)
 	for i := skip; ; i++ {
 	for i := skip; ; i++ {
 		pc, file, line, ok := runtime.Caller(i)
 		pc, file, line, ok := runtime.Caller(i)
-		if !ok {
+		//detect if caller is repeated to avoid loop, gccgo
+		//currently runs  into a loop without this check
+		if !ok || pc == prevPc {
 			break
 			break
 		}
 		}
 		frames = append(frames, NewFrame(pc, file, line))
 		frames = append(frames, NewFrame(pc, file, line))
+		prevPc = pc
 	}
 	}
 	return Stacktrace{
 	return Stacktrace{
 		Frames: frames,
 		Frames: frames,