// CopyToDir will copy all elements specified in the froms slice into the // directory inside the current ACI specified by the to string. func (a *ACBuild) CopyToDir(froms []string, to string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() target := path.Join(a.CurrentACIPath, aci.RootfsDir, to) targetInfo, err := os.Stat(target) switch { case os.IsNotExist(err): err := os.MkdirAll(target, 0755) if err != nil { return err } case err != nil: return err case !targetInfo.IsDir(): return fmt.Errorf("target %q is not a directory", to) } for _, from := range froms { _, file := path.Split(from) tmptarget := path.Join(target, file) err := fileutil.CopyTree(from, tmptarget, user.NewBlankUidRange()) if err != nil { return err } } return nil }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, img types.Hash, cdir string, useOverlay bool) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, 0755); err != nil { return fmt.Errorf("error creating stage1 directory: %v", err) } if err := cfg.Store.RenderTreeStore(img.String(), false); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } if err := cfg.Store.CheckTreeStore(img.String()); err != nil { log.Printf("Warning: tree cache is in a bad state. Rebuilding...") if err := cfg.Store.RenderTreeStore(img.String(), true); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } } if !useOverlay { if err := writeManifest(cfg.CommonConfig, img, s1); err != nil { return fmt.Errorf("error writing manifest: %v", err) } destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.Store.GetTreeStoreRootFS(img.String()) if err := fileutil.CopyTree(cachedTreePath, destRootfs); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } return nil }
func (e Engine) Run(command string, args []string, environment types.Environment, chroot, workingDir string) error { resolvConfFile := filepath.Join(chroot, "/etc/resolv.conf") _, err := os.Stat(resolvConfFile) switch { case os.IsNotExist(err): err := os.MkdirAll(filepath.Dir(resolvConfFile), 0755) if err != nil { return err } err = fileutil.CopyTree("/etc/resolv.conf", resolvConfFile, user.NewBlankUidRange()) if err != nil { return err } defer os.RemoveAll(resolvConfFile) case err != nil: return err } var serializedArgs string for _, arg := range args { if serializedArgs != "" { serializedArgs += "," } serializedArgs += arg } var serializedEnv string for _, envvar := range environment { if serializedEnv != "" { serializedEnv += "," } serializedEnv += envvar.Name + "=" + envvar.Value } path := "PATH=" for _, p := range engine.Pathlist { if path != "PATH=" { path += ":" } path += p } chrootArgs := []string{ "--cmd", command, "--chroot", chroot, "--working-dir", workingDir, } if len(serializedArgs) > 0 { chrootArgs = append(chrootArgs, "--args", serializedArgs) } if len(serializedEnv) > 0 { chrootArgs = append(chrootArgs, "--env", serializedEnv) } cmd := exec.Command("acbuild-chroot", chrootArgs...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Env = []string{path} return cmd.Run() }
func (a *ACBuild) beginFromLocalDirectory(start string) error { err := os.MkdirAll(a.CurrentACIPath, 0755) if err != nil { return err } err = fileutil.CopyTree(start, path.Join(a.CurrentACIPath, aci.RootfsDir), user.NewBlankUidRange()) if err != nil { return err } return a.writeEmptyManifest() }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, img types.Hash, cdir string, useOverlay bool) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, defaultRegularDirPerm); err != nil { return fmt.Errorf("error creating stage1 directory: %v", err) } treeStoreID, _, err := cfg.Store.RenderTreeStore(img.String(), false) if err != nil { return fmt.Errorf("error rendering tree image: %v", err) } if !cfg.SkipTreeStoreCheck { hash, err := cfg.Store.CheckTreeStore(treeStoreID) if err != nil { log.Printf("Warning: tree cache is in a bad state: %v. Rebuilding...", err) var err error treeStoreID, hash, err = cfg.Store.RenderTreeStore(img.String(), true) if err != nil { return fmt.Errorf("error rendering tree image: %v", err) } } cfg.CommonConfig.RootHash = hash } if err := writeManifest(*cfg.CommonConfig, img, s1); err != nil { return fmt.Errorf("error writing manifest: %v", err) } if !useOverlay { destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.Store.GetTreeStoreRootFS(treeStoreID) if err := fileutil.CopyTree(cachedTreePath, destRootfs, cfg.PrivateUsers); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } fn := path.Join(cdir, common.Stage1TreeStoreIDFilename) if err := ioutil.WriteFile(fn, []byte(treeStoreID), defaultRegularFilePerm); err != nil { return fmt.Errorf("error writing stage1 treeStoreID: %v", err) } return nil }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, cdir string) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, common.DefaultRegularDirPerm); err != nil { return errwrap.Wrap(errors.New("error creating stage1 directory"), err) } treeStoreID, _, err := cfg.TreeStore.Render(cfg.Stage1Image.String(), false) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), err) } if !cfg.SkipTreeStoreCheck { hash, err := cfg.TreeStore.Check(treeStoreID) if err != nil { log.Printf("warning: tree cache is in a bad state: %v. Rebuilding...", err) var err error treeStoreID, hash, err = cfg.TreeStore.Render(cfg.Stage1Image.String(), true) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), err) } } cfg.CommonConfig.RootHash = hash } if err := writeManifest(*cfg.CommonConfig, cfg.Stage1Image, s1); err != nil { return errwrap.Wrap(errors.New("error writing manifest"), err) } if !cfg.UseOverlay { destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.TreeStore.GetRootFS(treeStoreID) if err := fileutil.CopyTree(cachedTreePath, destRootfs, cfg.PrivateUsers); err != nil { return errwrap.Wrap(errors.New("error rendering ACI"), err) } } fn := path.Join(cdir, common.Stage1TreeStoreIDFilename) if err := ioutil.WriteFile(fn, []byte(treeStoreID), common.DefaultRegularFilePerm); err != nil { return errwrap.Wrap(errors.New("error writing stage1 treeStoreID"), err) } return nil }
// PrepareMountpoints creates and sets permissions for empty volumes. // If the mountpoint comes from a Docker image and it is an implicit empty // volume, we copy files from the image to the volume, see // https://docs.docker.com/engine/userguide/containers/dockervolumes/#data-volumes func PrepareMountpoints(volPath string, targetPath string, vol *types.Volume, dockerImplicit bool) error { if vol.Kind != "empty" { return nil } diag.Printf("creating an empty volume folder for sharing: %q", volPath) m, err := strconv.ParseUint(*vol.Mode, 8, 32) if err != nil { return errwrap.Wrap(fmt.Errorf("invalid mode %q for volume %q", *vol.Mode, vol.Name), err) } mode := os.FileMode(m) Uid := *vol.UID Gid := *vol.GID if dockerImplicit { fi, err := os.Stat(targetPath) if err == nil { // the directory exists in the image, let's set the same // permissions and copy files from there to the empty volume mode = fi.Mode() Uid = int(fi.Sys().(*syscall.Stat_t).Uid) Gid = int(fi.Sys().(*syscall.Stat_t).Gid) if err := fileutil.CopyTree(targetPath, volPath, user.NewBlankUidRange()); err != nil { return errwrap.Wrap(fmt.Errorf("error copying image files to empty volume %q", volPath), err) } } } if err := os.MkdirAll(volPath, 0770); err != nil { return errwrap.Wrap(fmt.Errorf("error creating %q", volPath), err) } if err := os.Chown(volPath, Uid, Gid); err != nil { return errwrap.Wrap(fmt.Errorf("could not change owner of %q", volPath), err) } if err := os.Chmod(volPath, mode); err != nil { return errwrap.Wrap(fmt.Errorf("could not change permissions of %q", volPath), err) } return nil }
// CreateBackup backs a directory up in a given directory. It basically // copies this directory into a given backups directory. The backups // directory has a simple structure - a directory inside named "0" is // the most recent backup. A directory name for oldest backup is // deduced from a given limit. For instance, for limit being 5 the // name for the oldest backup would be "4". If a backups number // exceeds the given limit then only newest ones are kept and the rest // is removed. func CreateBackup(dir, backupsDir string, limit int) error { tmpBackupDir := filepath.Join(backupsDir, "tmp") if err := os.MkdirAll(backupsDir, 0750); err != nil { return err } if err := fileutil.CopyTree(dir, tmpBackupDir, user.NewBlankUidRange()); err != nil { return err } defer os.RemoveAll(tmpBackupDir) // prune backups if err := pruneOldBackups(backupsDir, limit-1); err != nil { return err } if err := shiftBackups(backupsDir, limit-2); err != nil { return err } if err := os.Rename(tmpBackupDir, filepath.Join(backupsDir, "0")); err != nil { return err } return nil }
// createBackup backs a database up in a given directory. It basically // copies this directory into a given backups directory. The backups // directory has a simple structure - a directory inside named "0" is // the most recent backup. A directory name for oldest backup is // deduced from a given limit. For instance, for limit being 5 the // name for the oldest backup would be "4". If a backups number // exceeds the given limit then only newest ones are kept and the rest // is removed. func createBackup(dbDir, backupsDir string, limit int) error { tmpBackupDir := filepath.Join(backupsDir, "tmp") if err := os.MkdirAll(backupsDir, defaultPathPerm); err != nil { return err } if err := fileutil.CopyTree(dbDir, tmpBackupDir); err != nil { return err } defer os.RemoveAll(tmpBackupDir) // prune backups if err := pruneOldBackups(backupsDir, limit-1); err != nil { return err } if err := shiftBackups(backupsDir, limit-2); err != nil { return err } if err := os.Rename(tmpBackupDir, filepath.Join(backupsDir, "0")); err != nil { return err } return nil }
// CopyToTarget will copy a single file/directory from the from string to the // path specified by the to string inside the current ACI. func (a *ACBuild) CopyToTarget(from string, to string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() target := path.Join(a.CurrentACIPath, aci.RootfsDir, to) dir, _ := path.Split(target) if dir != "" { err := os.MkdirAll(dir, 0755) if err != nil { return err } } return fileutil.CopyTree(from, target, user.NewBlankUidRange()) }
func runImageExtract(cmd *cobra.Command, args []string) (exit int) { if len(args) != 2 { cmd.Usage() return 254 } outputDir := args[1] s, err := imagestore.NewStore(storeDir()) if err != nil { stderr.PrintE("cannot open store", err) return 254 } key, err := getStoreKeyFromAppOrHash(s, args[0]) if err != nil { stderr.Error(err) return 254 } aci, err := s.ReadStream(key) if err != nil { stderr.PrintE("error reading ACI from the store", err) return 254 } // ExtractTar needs an absolute path absOutputDir, err := filepath.Abs(outputDir) if err != nil { stderr.PrintE("error converting output to an absolute path", err) return 254 } if _, err := os.Stat(absOutputDir); err == nil { if !flagExtractOverwrite { stderr.Print("output directory exists (try --overwrite)") return 254 } // don't allow the user to delete the root filesystem by mistake if absOutputDir == "/" { stderr.Print("this would delete your root filesystem. Refusing.") return 254 } if err := os.RemoveAll(absOutputDir); err != nil { stderr.PrintE("error removing existing output dir", err) return 254 } } // if the user only asks for the rootfs we extract the image to a temporary // directory and then move/copy the rootfs to the output directory, if not // we just extract the image to the output directory extractDir := absOutputDir if flagExtractRootfsOnly { rktTmpDir, err := s.TmpDir() if err != nil { stderr.PrintE("error creating rkt temporary directory", err) return 254 } tmpDir, err := ioutil.TempDir(rktTmpDir, "rkt-image-extract-") if err != nil { stderr.PrintE("error creating temporary directory", err) return 254 } defer os.RemoveAll(tmpDir) extractDir = tmpDir } else { if err := os.MkdirAll(absOutputDir, 0755); err != nil { stderr.PrintE("error creating output directory", err) return 254 } } if err := tar.ExtractTar(aci, extractDir, false, user.NewBlankUidRange(), nil); err != nil { stderr.PrintE("error extracting ACI", err) return 254 } if flagExtractRootfsOnly { rootfsDir := filepath.Join(extractDir, "rootfs") if err := os.Rename(rootfsDir, absOutputDir); err != nil { if e, ok := err.(*os.LinkError); ok && e.Err == syscall.EXDEV { // it's on a different device, fall back to copying if err := fileutil.CopyTree(rootfsDir, absOutputDir, user.NewBlankUidRange()); err != nil { stderr.PrintE("error copying ACI rootfs", err) return 254 } } else { stderr.PrintE("error moving ACI rootfs", err) return 254 } } } return 0 }
func runImageRender(cmd *cobra.Command, args []string) (exit int) { if len(args) != 2 { cmd.Usage() return 254 } outputDir := args[1] s, err := imagestore.NewStore(storeDir()) if err != nil { stderr.PrintE("cannot open store", err) return 254 } ts, err := treestore.NewStore(treeStoreDir(), s) if err != nil { stderr.PrintE("cannot open store", err) return } key, err := getStoreKeyFromAppOrHash(s, args[0]) if err != nil { stderr.Error(err) return 254 } id, _, err := ts.Render(key, false) if err != nil { stderr.PrintE("error rendering ACI", err) return 254 } if _, err := ts.Check(id); err != nil { stderr.Print("warning: tree cache is in a bad state. Rebuilding...") var err error if id, _, err = ts.Render(key, true); err != nil { stderr.PrintE("error rendering ACI", err) return 254 } } if _, err := os.Stat(outputDir); err == nil { if !flagRenderOverwrite { stderr.Print("output directory exists (try --overwrite)") return 254 } // don't allow the user to delete the root filesystem by mistake if outputDir == "/" { stderr.Print("this would delete your root filesystem. Refusing.") return 254 } if err := os.RemoveAll(outputDir); err != nil { stderr.PrintE("error removing existing output dir", err) return 254 } } rootfsOutDir := outputDir if !flagRenderRootfsOnly { if err := os.MkdirAll(outputDir, 0755); err != nil { stderr.PrintE("error creating output directory", err) return 254 } rootfsOutDir = filepath.Join(rootfsOutDir, "rootfs") manifest, err := s.GetImageManifest(key) if err != nil { stderr.PrintE("error getting manifest", err) return 254 } mb, err := json.Marshal(manifest) if err != nil { stderr.PrintE("error marshalling image manifest", err) return 254 } if err := ioutil.WriteFile(filepath.Join(outputDir, "manifest"), mb, 0700); err != nil { stderr.PrintE("error writing image manifest", err) return 254 } } cachedTreePath := ts.GetRootFS(id) if err := fileutil.CopyTree(cachedTreePath, rootfsOutDir, user.NewBlankUidRange()); err != nil { stderr.PrintE("error copying ACI rootfs", err) return 254 } return 0 }
func runImageRender(cmd *cobra.Command, args []string) (exit int) { if len(args) != 2 { cmd.Usage() return 1 } outputDir := args[1] s, err := store.NewStore(globalFlags.Dir) if err != nil { stderr("image render: cannot open store: %v", err) return 1 } key, err := getKeyFromAppOrHash(s, args[0]) if err != nil { stderr("image render: %v", err) return 1 } if err := s.RenderTreeStore(key, false); err != nil { stderr("image render: error rendering ACI: %v", err) return 1 } if err := s.CheckTreeStore(key); err != nil { stderr("image render: warning: tree cache is in a bad state. Rebuilding...") if err := s.RenderTreeStore(key, true); err != nil { stderr("image render: error rendering ACI: %v", err) return 1 } } if _, err := os.Stat(outputDir); err == nil { if !flagRenderOverwrite { stderr("image render: output directory exists (try --overwrite)") return 1 } // don't allow the user to delete the root filesystem by mistake if outputDir == "/" { stderr("image extract: this would delete your root filesystem. Refusing.") return 1 } if err := os.RemoveAll(outputDir); err != nil { stderr("image render: error removing existing output dir: %v", err) return 1 } } rootfsOutDir := outputDir if !flagRenderRootfsOnly { if err := os.MkdirAll(outputDir, 0755); err != nil { stderr("image render: error creating output directory: %v", err) return 1 } rootfsOutDir = filepath.Join(rootfsOutDir, "rootfs") manifest, err := s.GetImageManifest(key) if err != nil { stderr("image render: error getting manifest: %v", err) return 1 } mb, err := json.Marshal(manifest) if err != nil { stderr("image render: error marshalling image manifest: %v", err) return 1 } if err := ioutil.WriteFile(filepath.Join(outputDir, "manifest"), mb, 0700); err != nil { stderr("image render: error writing image manifest: %v", err) return 1 } } cachedTreePath := s.GetTreeStoreRootFS(key) if err := fileutil.CopyTree(cachedTreePath, rootfsOutDir); err != nil { stderr("image render: error copying ACI rootfs: %v", err) return 1 } return 0 }