Browse code

Pass excludes/options to tar unarchiver via environment Fixes #10426

Because of the ability to easily overload the shell max argument list
length once the image count is several hundred, `docker load` will
start to fail because of this as it passes an excludes list of all
images in the graph. This patch uses an environment variable with the
json marshalled through it to get around the arg length limitation.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)

Phil Estes authored on 2015/01/30 00:28:44
Showing 1 changed files
... ...
@@ -1,7 +1,6 @@
1 1
 package chrootarchive
2 2
 
3 3
 import (
4
-	"bytes"
5 4
 	"encoding/json"
6 5
 	"flag"
7 6
 	"fmt"
... ...
@@ -9,7 +8,6 @@ import (
9 9
 	"os"
10 10
 	"path/filepath"
11 11
 	"runtime"
12
-	"strings"
13 12
 	"syscall"
14 13
 
15 14
 	"github.com/docker/docker/pkg/archive"
... ...
@@ -28,11 +26,14 @@ func chroot(path string) error {
28 28
 func untar() {
29 29
 	runtime.LockOSThread()
30 30
 	flag.Parse()
31
-	if err := chroot(flag.Arg(0)); err != nil {
31
+
32
+	var options *archive.TarOptions
33
+
34
+	if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
32 35
 		fatal(err)
33 36
 	}
34
-	var options *archive.TarOptions
35
-	if err := json.NewDecoder(strings.NewReader(flag.Arg(1))).Decode(&options); err != nil {
37
+
38
+	if err := chroot(flag.Arg(0)); err != nil {
36 39
 		fatal(err)
37 40
 	}
38 41
 	if err := archive.Unpack(os.Stdin, "/", options); err != nil {
... ...
@@ -54,27 +55,32 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error
54 54
 		options.ExcludePatterns = []string{}
55 55
 	}
56 56
 
57
-	var (
58
-		buf bytes.Buffer
59
-		enc = json.NewEncoder(&buf)
60
-	)
61
-	if err := enc.Encode(options); err != nil {
62
-		return fmt.Errorf("Untar json encode: %v", err)
63
-	}
57
+	dest = filepath.Clean(dest)
64 58
 	if _, err := os.Stat(dest); os.IsNotExist(err) {
65 59
 		if err := os.MkdirAll(dest, 0777); err != nil {
66 60
 			return err
67 61
 		}
68 62
 	}
69
-	dest = filepath.Clean(dest)
63
+
64
+	// We can't pass the exclude list directly via cmd line
65
+	// because we easily overrun the shell max argument list length
66
+	// when the full image list is passed (e.g. when this is used
67
+	// by `docker load`). Instead we will add the JSON marshalled
68
+	// and placed in the env, which has significantly larger
69
+	// max size
70
+	data, err := json.Marshal(options)
71
+	if err != nil {
72
+		return fmt.Errorf("Untar json encode: %v", err)
73
+	}
70 74
 	decompressedArchive, err := archive.DecompressStream(tarArchive)
71 75
 	if err != nil {
72 76
 		return err
73 77
 	}
74 78
 	defer decompressedArchive.Close()
75 79
 
76
-	cmd := reexec.Command("docker-untar", dest, buf.String())
80
+	cmd := reexec.Command("docker-untar", dest)
77 81
 	cmd.Stdin = decompressedArchive
82
+	cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
78 83
 	out, err := cmd.CombinedOutput()
79 84
 	if err != nil {
80 85
 		return fmt.Errorf("Untar %s %s", err, out)