mirror of https://github.com/docker/docs.git
				
				
				
			Merge pull request #2445 from alexlarsson/fix-shared-root-from-dm
Fix lxc start for shared root filesystems
This commit is contained in:
		
						commit
						629c6e3649
					
				
							
								
								
									
										27
									
								
								container.go
								
								
								
								
							
							
						
						
									
										27
									
								
								container.go
								
								
								
								
							|  | @ -894,7 +894,13 @@ func (container *Container) Start() (err error) { | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var lxcStart string = "lxc-start" | ||||
| 	if container.hostConfig.Privileged && container.runtime.capabilities.AppArmor { | ||||
| 		lxcStart = path.Join(container.runtime.config.Root, "lxc-start-unconfined") | ||||
| 	} | ||||
| 
 | ||||
| 	params := []string{ | ||||
| 		lxcStart, | ||||
| 		"-n", container.ID, | ||||
| 		"-f", container.lxcConfigPath(), | ||||
| 		"--", | ||||
|  | @ -987,11 +993,24 @@ func (container *Container) Start() (err error) { | |||
| 	params = append(params, "--", container.Path) | ||||
| 	params = append(params, container.Args...) | ||||
| 
 | ||||
| 	var lxcStart string = "lxc-start" | ||||
| 	if container.hostConfig.Privileged && container.runtime.capabilities.AppArmor { | ||||
| 		lxcStart = path.Join(container.runtime.config.Root, "lxc-start-unconfined") | ||||
| 	if RootIsShared() { | ||||
| 		// lxc-start really needs / to be non-shared, or all kinds of stuff break
 | ||||
| 		// when lxc-start unmount things and those unmounts propagate to the main
 | ||||
| 		// mount namespace.
 | ||||
| 		// What we really want is to clone into a new namespace and then
 | ||||
| 		// mount / MS_REC|MS_SLAVE, but since we can't really clone or fork
 | ||||
| 		// without exec in go we have to do this horrible shell hack...
 | ||||
| 		shellString := | ||||
| 			"mount --make-rslave /; exec " + | ||||
| 				utils.ShellQuoteArguments(params) | ||||
| 
 | ||||
| 		params = []string{ | ||||
| 			"unshare", "-m", "--", "/bin/sh", "-c", shellString, | ||||
| 		} | ||||
| 	} | ||||
| 	container.cmd = exec.Command(lxcStart, params...) | ||||
| 
 | ||||
| 	container.cmd = exec.Command(params[0], params[1:]...) | ||||
| 
 | ||||
| 	// Setup logging of stdout and stderr to disk
 | ||||
| 	if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil { | ||||
| 		return err | ||||
|  |  | |||
							
								
								
									
										15
									
								
								utils.go
								
								
								
								
							
							
						
						
									
										15
									
								
								utils.go
								
								
								
								
							|  | @ -4,6 +4,7 @@ import ( | |||
| 	"fmt" | ||||
| 	"github.com/dotcloud/docker/namesgenerator" | ||||
| 	"github.com/dotcloud/docker/utils" | ||||
| 	"io/ioutil" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | @ -310,6 +311,20 @@ func parseLink(rawLink string) (map[string]string, error) { | |||
| 	return utils.PartParser("name:alias", rawLink) | ||||
| } | ||||
| 
 | ||||
| func RootIsShared() bool { | ||||
| 	if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil { | ||||
| 		for _, line := range strings.Split(string(data), "\n") { | ||||
| 			cols := strings.Split(line, " ") | ||||
| 			if len(cols) >= 6 && cols[4] == "/" { | ||||
| 				return strings.HasPrefix(cols[6], "shared") | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// No idea, probably safe to assume so
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| type checker struct { | ||||
| 	runtime *Runtime | ||||
| } | ||||
|  |  | |||
|  | @ -1179,6 +1179,41 @@ func (e *StatusError) Error() string { | |||
| 	return fmt.Sprintf("Status: %d", e.Status) | ||||
| } | ||||
| 
 | ||||
| func quote(word string, buf *bytes.Buffer) { | ||||
| 	// Bail out early for "simple" strings
 | ||||
| 	if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") { | ||||
| 		buf.WriteString(word) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	buf.WriteString("'") | ||||
| 
 | ||||
| 	for i := 0; i < len(word); i++ { | ||||
| 		b := word[i] | ||||
| 		if b == '\'' { | ||||
| 			// Replace literal ' with a close ', a \', and a open '
 | ||||
| 			buf.WriteString("'\\''") | ||||
| 		} else { | ||||
| 			buf.WriteByte(b) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	buf.WriteString("'") | ||||
| } | ||||
| 
 | ||||
| // Take a list of strings and escape them so they will be handled right
 | ||||
| // when passed as arguments to an program via a shell
 | ||||
| func ShellQuoteArguments(args []string) string { | ||||
| 	var buf bytes.Buffer | ||||
| 	for i, arg := range args { | ||||
| 		if i != 0 { | ||||
| 			buf.WriteByte(' ') | ||||
| 		} | ||||
| 		quote(arg, &buf) | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
| 
 | ||||
| func IsClosedError(err error) bool { | ||||
| 	/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing. | ||||
| 	 * See: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue