github.com/rumpl/bof@v23.0.0-rc.2+incompatible/pkg/chrootarchive/diff_unix.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive" 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "flag" 10 "fmt" 11 "io" 12 "os" 13 "path/filepath" 14 "runtime" 15 16 "github.com/containerd/containerd/pkg/userns" 17 "github.com/docker/docker/pkg/archive" 18 "github.com/docker/docker/pkg/reexec" 19 "golang.org/x/sys/unix" 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 := userns.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 := unix.Umask(0) 46 defer unix.Umask(oldmask) 47 48 if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil { 49 fatal(err) 50 } 51 52 if inUserns { 53 options.InUserNS = true 54 } 55 56 if tmpDir, err = os.MkdirTemp("/", "temp-docker-extract"); err != nil { 57 fatal(err) 58 } 59 60 os.Setenv("TMPDIR", tmpDir) 61 size, err := archive.UnpackLayer("/", os.Stdin, options) 62 os.RemoveAll(tmpDir) 63 if err != nil { 64 fatal(err) 65 } 66 67 encoder := json.NewEncoder(os.Stdout) 68 if err := encoder.Encode(applyLayerResponse{size}); err != nil { 69 fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err)) 70 } 71 72 if _, err := flush(os.Stdin); err != nil { 73 fatal(err) 74 } 75 76 os.Exit(0) 77 } 78 79 // applyLayerHandler parses a diff in the standard layer format from `layer`, and 80 // applies it to the directory `dest`. Returns the size in bytes of the 81 // contents of the layer. 82 func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) { 83 dest = filepath.Clean(dest) 84 if decompress { 85 decompressed, err := archive.DecompressStream(layer) 86 if err != nil { 87 return 0, err 88 } 89 defer decompressed.Close() 90 91 layer = decompressed 92 } 93 if options == nil { 94 options = &archive.TarOptions{} 95 if userns.RunningInUserNS() { 96 options.InUserNS = true 97 } 98 } 99 if options.ExcludePatterns == nil { 100 options.ExcludePatterns = []string{} 101 } 102 103 data, err := json.Marshal(options) 104 if err != nil { 105 return 0, fmt.Errorf("ApplyLayer json encode: %v", err) 106 } 107 108 cmd := reexec.Command("docker-applyLayer", dest) 109 cmd.Stdin = layer 110 cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data)) 111 112 outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer) 113 cmd.Stdout, cmd.Stderr = outBuf, errBuf 114 115 if err = cmd.Run(); err != nil { 116 return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf) 117 } 118 119 // Stdout should be a valid JSON struct representing an applyLayerResponse. 120 response := applyLayerResponse{} 121 decoder := json.NewDecoder(outBuf) 122 if err = decoder.Decode(&response); err != nil { 123 return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err) 124 } 125 126 return response.LayerSize, nil 127 }