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