github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/chrootarchive/diff_unix.go (about) 1 //+build !windows 2 3 package chrootarchive // import "github.com/demonoid81/moby/pkg/chrootarchive" 4 5 import ( 6 "bytes" 7 "encoding/json" 8 "flag" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "runtime" 15 16 "github.com/demonoid81/moby/pkg/archive" 17 "github.com/demonoid81/moby/pkg/reexec" 18 "github.com/demonoid81/moby/pkg/system" 19 rsystem "github.com/opencontainers/runc/libcontainer/system" 20 ) 21 22 type applyLayerResponse struct { 23 LayerSize int64 `json:"layerSize"` 24 } 25 26 // applyLayer is the entry-point for docker-applylayer on re-exec. This is not 27 // used on Windows as it does not support chroot, hence no point sandboxing 28 // through chroot and rexec. 29 func applyLayer() { 30 31 var ( 32 tmpDir string 33 err error 34 options *archive.TarOptions 35 ) 36 runtime.LockOSThread() 37 flag.Parse() 38 39 inUserns := rsystem.RunningInUserNS() 40 if err := chroot(flag.Arg(0)); err != nil { 41 fatal(err) 42 } 43 44 // We need to be able to set any perms 45 oldmask, err := system.Umask(0) 46 defer system.Umask(oldmask) 47 if err != nil { 48 fatal(err) 49 } 50 51 if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil { 52 fatal(err) 53 } 54 55 if inUserns { 56 options.InUserNS = true 57 } 58 59 if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil { 60 fatal(err) 61 } 62 63 os.Setenv("TMPDIR", tmpDir) 64 size, err := archive.UnpackLayer("/", os.Stdin, options) 65 os.RemoveAll(tmpDir) 66 if err != nil { 67 fatal(err) 68 } 69 70 encoder := json.NewEncoder(os.Stdout) 71 if err := encoder.Encode(applyLayerResponse{size}); err != nil { 72 fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err)) 73 } 74 75 if _, err := flush(os.Stdin); err != nil { 76 fatal(err) 77 } 78 79 os.Exit(0) 80 } 81 82 // applyLayerHandler parses a diff in the standard layer format from `layer`, and 83 // applies it to the directory `dest`. Returns the size in bytes of the 84 // contents of the layer. 85 func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) { 86 dest = filepath.Clean(dest) 87 if decompress { 88 decompressed, err := archive.DecompressStream(layer) 89 if err != nil { 90 return 0, err 91 } 92 defer decompressed.Close() 93 94 layer = decompressed 95 } 96 if options == nil { 97 options = &archive.TarOptions{} 98 if rsystem.RunningInUserNS() { 99 options.InUserNS = true 100 } 101 } 102 if options.ExcludePatterns == nil { 103 options.ExcludePatterns = []string{} 104 } 105 106 data, err := json.Marshal(options) 107 if err != nil { 108 return 0, fmt.Errorf("ApplyLayer json encode: %v", err) 109 } 110 111 cmd := reexec.Command("docker-applyLayer", dest) 112 cmd.Stdin = layer 113 cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data)) 114 115 outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer) 116 cmd.Stdout, cmd.Stderr = outBuf, errBuf 117 118 if err = cmd.Run(); err != nil { 119 return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf) 120 } 121 122 // Stdout should be a valid JSON struct representing an applyLayerResponse. 123 response := applyLayerResponse{} 124 decoder := json.NewDecoder(outBuf) 125 if err = decoder.Decode(&response); err != nil { 126 return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err) 127 } 128 129 return response.LayerSize, nil 130 }