func TestChrootApplyDotDotFile(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyDotDotFile") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "..gitme"), []byte(""), 0644); err != nil { t.Fatal(err) } stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } if _, err := ApplyLayer(dest, stream); err != nil { t.Fatal(err) } }
// gh#10426: Verify the fix for having a huge excludes list (like on `docker load` with large # of // local images) func TestChrootUntarWithHugeExcludesList(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarHugeExcludes") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { t.Fatal(err) } stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } options := &archive.TarOptions{} //65534 entries of 64-byte strings ~= 4MB of environment space which should overflow //on most systems when passed via environment or command line arguments excludes := make([]string, 65534, 65534) for i := 0; i < 65534; i++ { excludes[i] = strings.Repeat(string(i), 64) } options.ExcludePatterns = excludes if err := Untar(stream, dest, options); err != nil { t.Fatal(err) } }
func TestChrootTarUntar(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntar") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "lolo"), []byte("hello lolo"), 0644); err != nil { t.Fatal(err) } stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "src") if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } if err := Untar(stream, dest, &archive.TarOptions{ExcludePatterns: []string{"lolo"}}); err != nil { t.Fatal(err) } }
// setupInitLayer populates a directory with mountpoints suitable // for bind-mounting dockerinit into the container. The mountpoint is simply an // empty file at /.dockerinit // // This extra layer is used by all containers as the top-most ro layer. It protects // the container from unwanted side-effects on the rw layer. func setupInitLayer(initLayer string) error { for pth, typ := range map[string]string{ "/dev/pts": "dir", "/dev/shm": "dir", "/proc": "dir", "/sys": "dir", "/.dockerinit": "file", "/.dockerenv": "file", "/etc/resolv.conf": "file", "/etc/hosts": "file", "/etc/hostname": "file", "/dev/console": "file", "/etc/mtab": "/proc/mounts", } { parts := strings.Split(pth, "/") prev := "/" for _, p := range parts[1:] { prev = filepath.Join(prev, p) syscall.Unlink(filepath.Join(initLayer, prev)) } if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil { if os.IsNotExist(err) { if err := system.MkdirAll(filepath.Join(initLayer, filepath.Dir(pth)), 0755); err != nil { return err } switch typ { case "dir": if err := system.MkdirAll(filepath.Join(initLayer, pth), 0755); err != nil { return err } case "file": f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755) if err != nil { return err } f.Close() default: if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil { return err } } } else { return err } } } // Layer is ready to use, if it wasn't before. return nil }
func TestChrootTarUntarWithSymlink(t *testing.T) { // TODO Windows: Figure out why this is failing if runtime.GOOS == "windows" { t.Skip("Failing on Windows") } tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntarWithSymlink") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, false); err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") if err := TarUntar(src, dest); err != nil { t.Fatal(err) } if err := compareDirectories(src, dest); err != nil { t.Fatal(err) } }
// tempDir returns the default directory to use for temporary files. func tempDir(rootDir string) (string, error) { var tmpDir string if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" { tmpDir = filepath.Join(rootDir, "tmp") } return tmpDir, system.MkdirAll(tmpDir, 0700) }
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir func (container *Container) SetupWorkingDirectory() error { if container.Config.WorkingDir == "" { return nil } // If can't mount container FS at this point (eg Hyper-V Containers on // Windows) bail out now with no action. if !container.canMountFS() { return nil } container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) pth, err := container.GetResourcePath(container.Config.WorkingDir) if err != nil { return err } if err := system.MkdirAll(pth, 0755); err != nil { pthInfo, err2 := os.Stat(pth) if err2 == nil && pthInfo != nil && !pthInfo.IsDir() { return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) } return err } return nil }
// mktemp creates a temporary sub-directory inside the graph's filesystem. func (graph *Graph) mktemp(id string) (string, error) { dir := filepath.Join(graph.root, "_tmp", stringid.GenerateNonCryptoID()) if err := system.MkdirAll(dir, 0700); err != nil { return "", err } return dir, nil }
// Save encodes and writes out all the authorization information func (configFile *ConfigFile) Save() error { // Encode sensitive data into a new/temp struct tmpAuthConfigs := make(map[string]AuthConfig, len(configFile.AuthConfigs)) for k, authConfig := range configFile.AuthConfigs { authCopy := authConfig // encode and save the authstring, while blanking out the original fields authCopy.Auth = EncodeAuth(&authCopy) authCopy.Username = "" authCopy.Password = "" authCopy.ServerAddress = "" tmpAuthConfigs[k] = authCopy } saveAuthConfigs := configFile.AuthConfigs configFile.AuthConfigs = tmpAuthConfigs defer func() { configFile.AuthConfigs = saveAuthConfigs }() data, err := json.MarshalIndent(configFile, "", "\t") if err != nil { return err } if err := system.MkdirAll(filepath.Dir(configFile.filename), 0700); err != nil { return err } if err := ioutil.WriteFile(configFile.filename, data, 0600); err != nil { return err } return nil }
// NewGraph instantiates a new graph at the given root path in the filesystem. // `root` will be created if it doesn't exist. func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) { abspath, err := filepath.Abs(root) if err != nil { return nil, err } // Create the root directory if it doesn't exists if err := system.MkdirAll(root, 0700); err != nil { return nil, err } graph := &Graph{ root: abspath, idIndex: truncindex.NewTruncIndex([]string{}), driver: driver, retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})}, } // Windows does not currently support tarsplit functionality. if runtime.GOOS == "windows" { graph.tarSplitDisabled = true } if err := graph.restore(); err != nil { return nil, err } return graph, nil }
// Setup sets up a mount point by either mounting the volume if it is // configured, or creating the source directory if supplied. func (m *MountPoint) Setup(mountLabel string) (string, error) { if m.Volume != nil { if m.ID == "" { m.ID = stringid.GenerateNonCryptoID() } return m.Volume.Mount(m.ID) } if len(m.Source) == 0 { return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined") } // system.MkdirAll() produces an error if m.Source exists and is a file (not a directory), if err := system.MkdirAll(m.Source, 0755); err != nil { if perr, ok := err.(*os.PathError); ok { if perr.Err != syscall.ENOTDIR { return "", err } } } if label.RelabelNeeded(m.Mode) { if err := label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)); err != nil { return "", err } } return m.Source, nil }
// Untar reads a stream of bytes from `archive`, parses it as a tar archive, // and unpacks it into the directory at `dest`. // The archive may be compressed with one of the following algorithms: // identity (uncompressed), gzip, bzip2, xz. func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { if err := system.MkdirAll(dest, 0777); err != nil { return err } } decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } defer decompressedArchive.Close() return invokeUnpack(decompressedArchive, dest, options) }
func (container *Container) setupWorkingDirectory() error { if container.Config.WorkingDir != "" { container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) pth, err := container.GetResourcePath(container.Config.WorkingDir) if err != nil { return err } pthInfo, err := os.Stat(pth) if err != nil { if !os.IsNotExist(err) { return err } if err := system.MkdirAll(pth, 0755); err != nil { return err } } if pthInfo != nil && !pthInfo.IsDir() { return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) } } return nil }
func (container *Container) setupWorkingDirectory() error { if container.Config.WorkingDir == "" { return nil } container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) pth, err := container.GetResourcePath(container.Config.WorkingDir) if err != nil { return err } pthInfo, err := os.Stat(pth) if err != nil { if !os.IsNotExist(err) { return err } if err := system.MkdirAll(pth, 0755); err != nil { return err } } if pthInfo != nil && !pthInfo.IsDir() { return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) } return nil }
func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { config.Root = rootDir // Create the root directory if it doesn't exists if err := system.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) { return err } return nil }
func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) { logrus.Debugf("CopyFileWithTar(%s, %s)", src, dst) srcSt, err := os.Stat(src) if err != nil { return err } if srcSt.IsDir() { return fmt.Errorf("Can't copy a directory") } // Clean up the trailing slash. This must be done in an operating // system specific manner. if dst[len(dst)-1] == os.PathSeparator { dst = filepath.Join(dst, filepath.Base(src)) } // Create the holding directory if necessary if err := system.MkdirAll(filepath.Dir(dst), 0700); err != nil && !os.IsExist(err) { return err } r, w := io.Pipe() errC := promise.Go(func() error { defer w.Close() srcF, err := os.Open(src) if err != nil { return err } defer srcF.Close() hdr, err := tar.FileInfoHeader(srcSt, "") if err != nil { return err } hdr.Name = filepath.Base(dst) hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode))) tw := tar.NewWriter(w) defer tw.Close() if err := tw.WriteHeader(hdr); err != nil { return err } if _, err := io.Copy(tw, srcF); err != nil { return err } return nil }) defer func() { if er := <-errC; err != nil { err = er } }() return archiver.Untar(r, filepath.Dir(dst), nil) }
// New creates a fresh instance of libcontainerd remote. func New(stateDir string, options ...RemoteOption) (_ Remote, err error) { defer func() { if err != nil { err = fmt.Errorf("Failed to connect to containerd. Please make sure containerd is installed in your PATH or you have specificed the correct address. Got error: %v", err) } }() r := &remote{ stateDir: stateDir, daemonPid: -1, eventTsPath: filepath.Join(stateDir, eventTimestampFilename), pastEvents: make(map[string]*containerd.Event), } for _, option := range options { if err := option.Apply(r); err != nil { return nil, err } } if err := sysinfo.MkdirAll(stateDir, 0700); err != nil { return nil, err } if r.rpcAddr == "" { r.rpcAddr = filepath.Join(stateDir, containerdSockFilename) } if r.startDaemon { if err := r.runContainerdDaemon(); err != nil { return nil, err } } // don't output the grpc reconnect logging grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags)) dialOpts := append([]grpc.DialOption{grpc.WithInsecure()}, grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { return net.DialTimeout("unix", addr, timeout) }), ) conn, err := grpc.Dial(r.rpcAddr, dialOpts...) if err != nil { return nil, fmt.Errorf("error connecting to containerd: %v", err) } r.rpcConn = conn r.apiClient = containerd.NewAPIClient(conn) go r.handleConnectionChange() if err := r.startEventsMonitor(); err != nil { return nil, err } return r, nil }
// New creates a PIDfile using the specified path. func New(path string) (*PIDFile, error) { if err := checkPIDFileAlreadyExists(path); err != nil { return nil, err } // Note MkdirAll returns nil if a directory already exists if err := system.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil { return nil, err } if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil { return nil, err } return &PIDFile{path: path}, nil }
func TestChrootCopyWithTar(t *testing.T) { // TODO Windows: Figure out why this is failing if runtime.GOOS == "windows" || runtime.GOOS == "solaris" { t.Skip("Failing on Windows and Solaris") } tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyWithTar") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { t.Fatal(err) } // Copy directory dest := filepath.Join(tmpdir, "dest") if err := CopyWithTar(src, dest); err != nil { t.Fatal(err) } if err := compareDirectories(src, dest); err != nil { t.Fatal(err) } // Copy file srcfile := filepath.Join(src, "file-1") dest = filepath.Join(tmpdir, "destFile") destfile := filepath.Join(dest, "file-1") if err := CopyWithTar(srcfile, destfile); err != nil { t.Fatal(err) } if err := compareFiles(srcfile, destfile); err != nil { t.Fatal(err) } // Copy symbolic link srcLinkfile := filepath.Join(src, "file-1-link") dest = filepath.Join(tmpdir, "destSymlink") destLinkfile := filepath.Join(dest, "file-1-link") if err := CopyWithTar(srcLinkfile, destLinkfile); err != nil { t.Fatal(err) } if err := compareFiles(srcLinkfile, destLinkfile); err != nil { t.Fatal(err) } }
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { // make an array containing the original path asked for, plus (for mkAll == true) // all path components leading up to the complete path that don't exist before we MkdirAll // so that we can chown all of them properly at the end. If chownExisting is false, we won't // chown the full directory path if it exists var paths []string if _, err := os.Stat(path); err != nil && os.IsNotExist(err) { paths = []string{path} } else if err == nil && chownExisting { if err := os.Chown(path, ownerUID, ownerGID); err != nil { return err } // short-circuit--we were called with an existing directory and chown was requested return nil } else if err == nil { // nothing to do; directory path fully exists already and chown was NOT requested return nil } if mkAll { // walk back to "/" looking for directories which do not exist // and add them to the paths array for chown after creation dirPath := path for { dirPath = filepath.Dir(dirPath) if dirPath == "/" { break } if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { paths = append(paths, dirPath) } } if err := system.MkdirAll(path, mode); err != nil && !os.IsExist(err) { return err } } else { if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) { return err } } // even if it existed, we will chown the requested path + any subpaths that // didn't exist when we called MkdirAll for _, pathComponent := range paths { if err := os.Chown(pathComponent, ownerUID, ownerGID); err != nil { return err } } return nil }
// Save encodes and writes out all the authorization information func (configFile *ConfigFile) Save() error { if configFile.Filename() == "" { return fmt.Errorf("Can't save config with empty filename") } if err := system.MkdirAll(filepath.Dir(configFile.filename), 0700); err != nil { return err } f, err := os.OpenFile(configFile.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } defer f.Close() return configFile.SaveToWriter(f) }
func TestChrootApplyEmptyArchiveFromSlowReader(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyEmptyArchiveFromSlowReader") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) dest := filepath.Join(tmpdir, "dest") if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024} if _, err := ApplyLayer(dest, stream); err != nil { t.Fatal(err) } }
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll bool) error { if mkAll { if err := system.MkdirAll(path, mode); err != nil && !os.IsExist(err) { return err } } else { if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) { return err } } // even if it existed, we will chown to change ownership as requested if err := os.Chown(path, ownerUID, ownerGID); err != nil { return err } return nil }
func (archiver *Archiver) CopyWithTar(src, dst string) error { srcSt, err := os.Stat(src) if err != nil { return err } if !srcSt.IsDir() { return archiver.CopyFileWithTar(src, dst) } // Create dst, copy src's content into it logrus.Debugf("Creating dest directory: %s", dst) if err := system.MkdirAll(dst, 0755); err != nil && !os.IsExist(err) { return err } logrus.Debugf("Calling TarUntar(%s, %s)", src, dst) return archiver.TarUntar(src, dst) }
func TestChrootCopyWithTar(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyWithTar") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { t.Fatal(err) } // Copy directory dest := filepath.Join(tmpdir, "dest") if err := CopyWithTar(src, dest); err != nil { t.Fatal(err) } if err := compareDirectories(src, dest); err != nil { t.Fatal(err) } // Copy file srcfile := filepath.Join(src, "file-1") dest = filepath.Join(tmpdir, "destFile") destfile := filepath.Join(dest, "file-1") if err := CopyWithTar(srcfile, destfile); err != nil { t.Fatal(err) } if err := compareFiles(srcfile, destfile); err != nil { t.Fatal(err) } // Copy symbolic link srcLinkfile := filepath.Join(src, "file-1-link") dest = filepath.Join(tmpdir, "destSymlink") destLinkfile := filepath.Join(dest, "file-1-link") if err := CopyWithTar(srcLinkfile, destLinkfile); err != nil { t.Fatal(err) } if err := compareFiles(srcLinkfile, destLinkfile); err != nil { t.Fatal(err) } }
func migrateKey(config *daemon.Config) (err error) { // No migration necessary on Windows if runtime.GOOS == "windows" { return nil } // Migrate trust key if exists at ~/.docker/key.json and owned by current user oldPath := filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) newPath := filepath.Join(getDaemonConfDir(config.Root), cliflags.DefaultTrustKeyFile) if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) { defer func() { // Ensure old path is removed if no error occurred if err == nil { err = os.Remove(oldPath) } else { logrus.Warnf("Key migration failed, key file not removed at %s", oldPath) os.Remove(newPath) } }() if err := system.MkdirAll(getDaemonConfDir(config.Root), os.FileMode(0644)); err != nil { return fmt.Errorf("Unable to create daemon configuration directory: %s", err) } newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return fmt.Errorf("error creating key file %q: %s", newPath, err) } defer newFile.Close() oldFile, err := os.Open(oldPath) if err != nil { return fmt.Errorf("error opening key file %q: %s", oldPath, err) } defer oldFile.Close() if _, err := io.Copy(newFile, oldFile); err != nil { return fmt.Errorf("error copying key: %s", err) } logrus.Infof("Migrated key from %s to %s", oldPath, newPath) } return nil }
func (m *mountPoint) Setup() (string, error) { if m.Volume != nil { return m.Volume.Mount() } if len(m.Source) > 0 { if _, err := os.Stat(m.Source); err != nil { if !os.IsNotExist(err) { return "", err } if err := system.MkdirAll(m.Source, 0755); err != nil { return "", err } } return m.Source, nil } return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined") }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) } return trustKey, nil }
// Setup sets up a mount point by either mounting the volume if it is // configured, or creating the source directory if supplied. func (m *mountPoint) Setup() (string, error) { if m.Volume != nil { return m.Volume.Mount() } if len(m.Source) > 0 { if _, err := os.Stat(m.Source); err != nil { if !os.IsNotExist(err) { return "", err } if err := system.MkdirAll(m.Source, 0755); err != nil { return "", err } } return m.Source, nil } return "", derr.ErrorCodeMountSetup }
// Setup sets up a mount point by either mounting the volume if it is // configured, or creating the source directory if supplied. func (m *MountPoint) Setup() (string, error) { if m.Volume != nil { return m.Volume.Mount() } if len(m.Source) > 0 { if _, err := os.Stat(m.Source); err != nil { if !os.IsNotExist(err) { return "", err } if runtime.GOOS != "windows" { // Windows does not have deprecation issues here logrus.Warnf("Auto-creating non-existent volume host path %s, this is deprecated and will be removed soon", m.Source) if err := system.MkdirAll(m.Source, 0755); err != nil { return "", err } } } return m.Source, nil } return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined") }