mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
4347080b46
It was only used in a couple of places, and in most places shouldn't be used as those locations were in unix/linux-only files, so didn't need the wrapper. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
133 lines
3.3 KiB
Go
133 lines
3.3 KiB
Go
//go:build !windows
|
|
// +build !windows
|
|
|
|
package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"github.com/containerd/containerd/pkg/userns"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/docker/docker/pkg/reexec"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
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 := userns.RunningInUserNS()
|
|
if err := chroot(flag.Arg(0)); err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
// We need to be able to set any perms
|
|
oldmask := unix.Umask(0)
|
|
defer unix.Umask(oldmask)
|
|
|
|
if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
if inUserns {
|
|
options.InUserNS = true
|
|
}
|
|
|
|
if tmpDir, err = os.MkdirTemp("/", "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 userns.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
|
|
|
|
// reexec.Command() sets cmd.SysProcAttr.Pdeathsig on Linux, which
|
|
// causes the started process to be signaled when the creating OS thread
|
|
// dies. Ensure that the reexec is not prematurely signaled. See
|
|
// https://go.dev/issue/27505 for more information.
|
|
runtime.LockOSThread()
|
|
defer runtime.UnlockOSThread()
|
|
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
|
|
}
|