2015-06-01 19:42:27 -04:00
|
|
|
//+build !windows
|
|
|
|
|
2014-10-29 15:06:51 -04:00
|
|
|
package chrootarchive
|
|
|
|
|
|
|
|
import (
|
2014-12-17 21:26:03 -05:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2014-10-29 15:06:51 -04:00
|
|
|
"flag"
|
|
|
|
"fmt"
|
2016-10-20 19:40:59 -04:00
|
|
|
"io"
|
2014-11-18 16:33:13 -05:00
|
|
|
"io/ioutil"
|
2014-10-29 15:06:51 -04:00
|
|
|
"os"
|
2014-12-08 16:14:56 -05:00
|
|
|
"path/filepath"
|
2014-10-29 15:06:51 -04:00
|
|
|
"runtime"
|
|
|
|
|
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
|
|
"github.com/docker/docker/pkg/reexec"
|
2015-05-14 18:08:00 -04:00
|
|
|
"github.com/docker/docker/pkg/system"
|
2016-02-12 19:05:50 -05:00
|
|
|
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
2014-10-29 15:06:51 -04:00
|
|
|
)
|
|
|
|
|
2014-12-17 21:26:03 -05:00
|
|
|
type applyLayerResponse struct {
|
|
|
|
LayerSize int64 `json:"layerSize"`
|
|
|
|
}
|
|
|
|
|
2015-06-01 19:42:27 -04:00
|
|
|
// applyLayer is the entry-point for docker-applylayer on re-exec. This is not
|
|
|
|
// used on Windows as it does not support chroot, hence no point sandboxing
|
|
|
|
// through chroot and rexec.
|
2014-10-29 15:06:51 -04:00
|
|
|
func applyLayer() {
|
2015-05-14 18:08:00 -04:00
|
|
|
|
|
|
|
var (
|
2016-11-29 03:17:35 -05:00
|
|
|
tmpDir string
|
2015-10-08 11:51:41 -04:00
|
|
|
err error
|
|
|
|
options *archive.TarOptions
|
2015-05-14 18:08:00 -04:00
|
|
|
)
|
2014-10-29 15:06:51 -04:00
|
|
|
runtime.LockOSThread()
|
|
|
|
flag.Parse()
|
|
|
|
|
2016-02-12 19:05:50 -05:00
|
|
|
inUserns := rsystem.RunningInUserNS()
|
2015-06-01 19:42:27 -04:00
|
|
|
if err := chroot(flag.Arg(0)); err != nil {
|
|
|
|
fatal(err)
|
|
|
|
}
|
2015-05-14 18:08:00 -04:00
|
|
|
|
2015-06-01 19:42:27 -04:00
|
|
|
// We need to be able to set any perms
|
|
|
|
oldmask, err := system.Umask(0)
|
|
|
|
defer system.Umask(oldmask)
|
|
|
|
if err != nil {
|
|
|
|
fatal(err)
|
2014-10-29 15:06:51 -04:00
|
|
|
}
|
2014-12-17 21:26:03 -05:00
|
|
|
|
2015-10-08 11:51:41 -04:00
|
|
|
if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
|
|
|
|
fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-02-12 19:05:50 -05:00
|
|
|
if inUserns {
|
|
|
|
options.InUserNS = true
|
|
|
|
}
|
|
|
|
|
2015-06-01 19:42:27 -04:00
|
|
|
if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil {
|
2014-11-18 16:33:13 -05:00
|
|
|
fatal(err)
|
|
|
|
}
|
2014-12-17 21:26:03 -05:00
|
|
|
|
2014-11-18 16:33:13 -05:00
|
|
|
os.Setenv("TMPDIR", tmpDir)
|
2015-10-08 11:51:41 -04:00
|
|
|
size, err := archive.UnpackLayer("/", os.Stdin, options)
|
2014-12-08 16:14:56 -05:00
|
|
|
os.RemoveAll(tmpDir)
|
|
|
|
if err != nil {
|
2014-10-29 15:06:51 -04:00
|
|
|
fatal(err)
|
|
|
|
}
|
2014-12-17 21:26:03 -05:00
|
|
|
|
|
|
|
encoder := json.NewEncoder(os.Stdout)
|
|
|
|
if err := encoder.Encode(applyLayerResponse{size}); err != nil {
|
|
|
|
fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err))
|
|
|
|
}
|
|
|
|
|
2016-03-14 16:22:05 -04:00
|
|
|
if _, err := flush(os.Stdin); err != nil {
|
|
|
|
fatal(err)
|
|
|
|
}
|
|
|
|
|
2014-10-29 15:06:51 -04:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:04:36 -04:00
|
|
|
// applyLayerHandler parses a diff in the standard layer format from `layer`, and
|
|
|
|
// applies it to the directory `dest`. Returns the size in bytes of the
|
|
|
|
// contents of the layer.
|
2016-10-20 19:40:59 -04:00
|
|
|
func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) {
|
2014-12-08 16:14:56 -05:00
|
|
|
dest = filepath.Clean(dest)
|
2015-07-27 09:46:20 -04:00
|
|
|
if decompress {
|
|
|
|
decompressed, err := archive.DecompressStream(layer)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
defer decompressed.Close()
|
|
|
|
|
|
|
|
layer = decompressed
|
2014-12-08 16:14:56 -05:00
|
|
|
}
|
2015-10-08 11:51:41 -04:00
|
|
|
if options == nil {
|
|
|
|
options = &archive.TarOptions{}
|
2016-02-12 19:05:50 -05:00
|
|
|
if rsystem.RunningInUserNS() {
|
|
|
|
options.InUserNS = true
|
|
|
|
}
|
2015-10-08 11:51:41 -04:00
|
|
|
}
|
|
|
|
if options.ExcludePatterns == nil {
|
|
|
|
options.ExcludePatterns = []string{}
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := json.Marshal(options)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("ApplyLayer json encode: %v", err)
|
|
|
|
}
|
2014-12-17 21:26:03 -05:00
|
|
|
|
2014-10-29 15:06:51 -04:00
|
|
|
cmd := reexec.Command("docker-applyLayer", dest)
|
2015-07-27 09:46:20 -04:00
|
|
|
cmd.Stdin = layer
|
2015-10-08 11:51:41 -04:00
|
|
|
cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
|
2014-12-17 21:26:03 -05:00
|
|
|
|
|
|
|
outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
|
|
|
|
cmd.Stdout, cmd.Stderr = outBuf, errBuf
|
|
|
|
|
|
|
|
if err = cmd.Run(); err != nil {
|
|
|
|
return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stdout should be a valid JSON struct representing an applyLayerResponse.
|
|
|
|
response := applyLayerResponse{}
|
|
|
|
decoder := json.NewDecoder(outBuf)
|
|
|
|
if err = decoder.Decode(&response); err != nil {
|
|
|
|
return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err)
|
2014-10-29 15:06:51 -04:00
|
|
|
}
|
2014-12-17 21:26:03 -05:00
|
|
|
|
|
|
|
return response.LayerSize, nil
|
2014-10-29 15:06:51 -04:00
|
|
|
}
|