github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/pkg/chrootarchive/archive_unix.go (about)

     1  // +build !windows
     2  
     3  package chrootarchive
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/json"
     8  	"flag"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"runtime"
    14  
    15  	"github.com/docker/docker/pkg/archive"
    16  	"github.com/docker/docker/pkg/reexec"
    17  )
    18  
    19  // untar is the entry-point for docker-untar on re-exec. This is not used on
    20  // Windows as it does not support chroot, hence no point sandboxing through
    21  // chroot and rexec.
    22  func untar() {
    23  	runtime.LockOSThread()
    24  	flag.Parse()
    25  
    26  	var options *archive.TarOptions
    27  
    28  	//read the options from the pipe "ExtraFiles"
    29  	if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&options); err != nil {
    30  		fatal(err)
    31  	}
    32  
    33  	if err := chroot(flag.Arg(0)); err != nil {
    34  		fatal(err)
    35  	}
    36  
    37  	if err := archive.Unpack(os.Stdin, "/", options); err != nil {
    38  		fatal(err)
    39  	}
    40  	// fully consume stdin in case it is zero padded
    41  	if _, err := flush(os.Stdin); err != nil {
    42  		fatal(err)
    43  	}
    44  
    45  	os.Exit(0)
    46  }
    47  
    48  func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions) error {
    49  
    50  	// We can't pass a potentially large exclude list directly via cmd line
    51  	// because we easily overrun the kernel's max argument/environment size
    52  	// when the full image list is passed (e.g. when this is used by
    53  	// `docker load`). We will marshall the options via a pipe to the
    54  	// child
    55  	r, w, err := os.Pipe()
    56  	if err != nil {
    57  		return fmt.Errorf("Untar pipe failure: %v", err)
    58  	}
    59  
    60  	cmd := reexec.Command("docker-untar", dest)
    61  	cmd.Stdin = decompressedArchive
    62  
    63  	cmd.ExtraFiles = append(cmd.ExtraFiles, r)
    64  	output := bytes.NewBuffer(nil)
    65  	cmd.Stdout = output
    66  	cmd.Stderr = output
    67  
    68  	if err := cmd.Start(); err != nil {
    69  		return fmt.Errorf("Untar error on re-exec cmd: %v", err)
    70  	}
    71  	//write the options to the pipe for the untar exec to read
    72  	if err := json.NewEncoder(w).Encode(options); err != nil {
    73  		return fmt.Errorf("Untar json encode to pipe failed: %v", err)
    74  	}
    75  	w.Close()
    76  
    77  	if err := cmd.Wait(); err != nil {
    78  		// when `xz -d -c -q | docker-untar ...` failed on docker-untar side,
    79  		// we need to exhaust `xz`'s output, otherwise the `xz` side will be
    80  		// pending on write pipe forever
    81  		io.Copy(ioutil.Discard, decompressedArchive)
    82  
    83  		return fmt.Errorf("Error processing tar file(%v): %s", err, output)
    84  	}
    85  	return nil
    86  }