mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
9ff990a2b9
The implementation in libcontainer/system is quite complicated, and we only use it to detect if user-namespaces are enabled. In addition, the implementation in containerd uses a sync.Once, so that detection (and reading/parsing `/proc/self/uid_map`) is only performed once. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
130 lines
3 KiB
Go
130 lines
3 KiB
Go
//+build !windows
|
|
|
|
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"github.com/containerd/containerd/sys"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/docker/docker/pkg/reexec"
|
|
"github.com/docker/docker/pkg/system"
|
|
)
|
|
|
|
type applyLayerResponse struct {
|
|
LayerSize int64 `json:"layerSize"`
|
|
}
|
|
|
|
// 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.
|
|
func applyLayer() {
|
|
|
|
var (
|
|
tmpDir string
|
|
err error
|
|
options *archive.TarOptions
|
|
)
|
|
runtime.LockOSThread()
|
|
flag.Parse()
|
|
|
|
inUserns := sys.RunningInUserNS()
|
|
if err := chroot(flag.Arg(0)); err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
// We need to be able to set any perms
|
|
oldmask, err := system.Umask(0)
|
|
defer system.Umask(oldmask)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
if inUserns {
|
|
options.InUserNS = true
|
|
}
|
|
|
|
if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
os.Setenv("TMPDIR", tmpDir)
|
|
size, err := archive.UnpackLayer("/", os.Stdin, options)
|
|
os.RemoveAll(tmpDir)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
encoder := json.NewEncoder(os.Stdout)
|
|
if err := encoder.Encode(applyLayerResponse{size}); err != nil {
|
|
fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err))
|
|
}
|
|
|
|
if _, err := flush(os.Stdin); err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
os.Exit(0)
|
|
}
|
|
|
|
// 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.
|
|
func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) {
|
|
dest = filepath.Clean(dest)
|
|
if decompress {
|
|
decompressed, err := archive.DecompressStream(layer)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer decompressed.Close()
|
|
|
|
layer = decompressed
|
|
}
|
|
if options == nil {
|
|
options = &archive.TarOptions{}
|
|
if sys.RunningInUserNS() {
|
|
options.InUserNS = true
|
|
}
|
|
}
|
|
if options.ExcludePatterns == nil {
|
|
options.ExcludePatterns = []string{}
|
|
}
|
|
|
|
data, err := json.Marshal(options)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("ApplyLayer json encode: %v", err)
|
|
}
|
|
|
|
cmd := reexec.Command("docker-applyLayer", dest)
|
|
cmd.Stdin = layer
|
|
cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
|
|
|
|
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)
|
|
}
|
|
|
|
return response.LayerSize, nil
|
|
}
|