// copyAttachment makes a copy of a file that is in the volatile content hub cache func copyAttachment(src string) (string, error) { _, b := filepath.Split(src) dest := filepath.Join(attachDir, b) err := helpers.CopyFile(src, dest, helpers.CopyFlagOverwrite) if err != nil { return "", err } return dest, nil }
// iterOp iterates over all the files found with the given glob, making the // basename (with the given prefix prepended) the target file in the given // target directory. It then performs op on that target file: either copying // from the globbed file to the target file, or removing the target file. // Directories are created as needed. Errors out with any of the things that // could go wrong with this, including a file found by glob not being a // regular file. func iterOp(op policyOp, glob, targetDir, prefix string) (err error) { if err = os.MkdirAll(targetDir, 0755); err != nil { return fmt.Errorf("unable to make %v directory: %v", targetDir, err) } files, err := filepath.Glob(glob) if err != nil { // filepath.Glob seems to not return errors ever right // now. This might be a bug in Go, or it might be by // design. Better play safe. return fmt.Errorf("unable to glob %v: %v", glob, err) } for _, file := range files { s, err := os.Lstat(file) if err != nil { return fmt.Errorf("unable to stat %v: %v", file, err) } if !s.Mode().IsRegular() { return fmt.Errorf("unable to do %s for %v: not a regular file", op, file) } targetFile := filepath.Join(targetDir, prefix+filepath.Base(file)) switch op { case remove: if err := os.Remove(targetFile); err != nil { return fmt.Errorf("unable to remove %v: %v", targetFile, err) } case install: // do the copy if err := helpers.CopyFile(file, targetFile, helpers.CopyFlagSync|helpers.CopyFlagOverwrite); err != nil { return err } default: return fmt.Errorf("unknown operation %s", op) } } return nil }
func copyKernelAssets(prefixDir, grubTargetDir string) error { for _, p := range []string{"/boot/vmlinuz-*", "/boot/initrd.img-*"} { matches, err := filepath.Glob(filepath.Join(prefixDir, p)) if err != nil { return err } if len(matches) != 1 { return fmt.Errorf("Incorrect matches for %v: %v", p, matches) } name := normalizeKernelInitrdName(filepath.Base(matches[0])) targetPath := filepath.Join(bootloaderGrubDir(), grubTargetDir, name) os.MkdirAll(filepath.Dir(targetPath), 0755) // FIXME: valid? if helpers.FileExists(targetPath) { continue } if err := helpers.CopyFile(matches[0], targetPath, 0); err != nil { return err } logger.Noticef("Copied file %v -> %v", matches[0], targetPath) } return nil }
// getTimezone returns the current timezone the system is set to or an error // if it can't. var getTimezone = func() (timezone string, err error) { tz, err := ioutil.ReadFile(tzFile()) if err != nil { return "", err } return strings.TrimSpace(string(tz)), nil } // setTimezone sets the specified timezone for the system, an error is returned // if it can't. var setTimezone = func(timezone string) error { if err := helpers.CopyFile(filepath.Join(tzZoneInfoPath, timezone), tzZoneInfoTarget, helpers.CopyFlagOverwrite); err != nil { return err } return helpers.AtomicWriteFile(tzFile(), []byte(timezone), 0644, helpers.AtomicWriteFollow) } func getPassthrough(rootDir string) (pc []passthroughConfig, err error) { filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } content, err := ioutil.ReadFile(path) if err != nil { return err }
func copyToBuildDir(sourceDir, buildDir string) error { sourceDir, err := filepath.Abs(sourceDir) if err != nil { return err } err = os.Remove(buildDir) if err != nil && !os.IsNotExist(err) { // this shouldn't happen, but. return err } // no umask here so that we get the permissions correct oldUmask := syscall.Umask(0) defer syscall.Umask(oldUmask) return filepath.Walk(sourceDir, func(path string, info os.FileInfo, errin error) (err error) { if errin != nil { return errin } relpath := path[len(sourceDir):] if relpath == "/DEBIAN" || shouldExclude(sourceDir, filepath.Base(path)) { if info.IsDir() { return filepath.SkipDir } return nil } dest := filepath.Join(buildDir, relpath) // handle dirs if info.IsDir() { return os.Mkdir(dest, info.Mode()) } // handle char/block devices if helpers.IsDevice(info.Mode()) { return helpers.CopySpecialFile(path, dest) } if (info.Mode() & os.ModeSymlink) != 0 { target, err := os.Readlink(path) if err != nil { return err } return os.Symlink(target, dest) } // fail if its unsupported if !info.Mode().IsRegular() { return fmt.Errorf("can not handle type of file %s", path) } // it's a file. Maybe we can link it? if os.Link(path, dest) == nil { // whee return nil } // sigh. ok, copy it is. return helpers.CopyFile(path, dest, helpers.CopyFlagDefault) }) }
func customizeClassicChroot() error { // create the snappy mountpoint if err := os.MkdirAll(filepath.Join(dirs.ClassicDir, "snappy"), 0755); err != nil { return fmt.Errorf("failed to create snappy mount point: %s", err) } // copy configs for _, f := range []string{"hostname", "hosts", "timezone", "localtime"} { src := filepath.Join("/etc/", f) dst := filepath.Join(dirs.ClassicDir, "etc", f) if err := helpers.CopyFile(src, dst, helpers.CopyFlagPreserveAll); err != nil { return err } } // ensure daemons do not start if err := ioutil.WriteFile(filepath.Join(dirs.ClassicDir, "/usr/sbin/policy-rc.d"), policyRc, 0755); err != nil { return fmt.Errorf("failed to write policy-rc.d: %s", err) } // remove ubuntu user, will come from snappy OS if err := runInChroot(dirs.ClassicDir, "deluser", "ubuntu"); err != nil { return err } // install extra packages; make sure chroot can resolve DNS resolveDir := filepath.Join(dirs.ClassicDir, "/run/resolvconf/") if err := os.MkdirAll(resolveDir, 0755); err != nil { return fmt.Errorf("failed to create %s: %s", resolveDir, err) } src := filepath.Join(dirs.GlobalRootDir, "/run/resolvconf/resolv.conf") dst := filepath.Join(dirs.ClassicDir, "/run/resolvconf/") if err := helpers.CopyFile(src, dst, helpers.CopyFlagPreserveAll); err != nil { return err } // enable libnss-extrausers if err := runInChroot(dirs.ClassicDir, "apt-get", "install", "-y", "libnss-extrausers"); err != nil { return err } // this regexp adds "extrausers" after the passwd/group/shadow // lines in /etc/nsswitch.conf cmd := exec.Command("sed", "-i", "-r", "/^(passwd|group|shadow):/ s/$/ extrausers/", filepath.Join(dirs.ClassicDir, "/etc/nsswitch.conf")) if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to enable libness-extrausers: %s", output) } // clean up cruft (bad lxd rootfs!) if output, err := exec.Command("sh", "-c", fmt.Sprintf("rm -rf %s/run/*", dirs.ClassicDir)).CombinedOutput(); err != nil { return fmt.Errorf("failed to cleanup classic /run dir: %s (%s)", err, output) } // Add hosts "sudo" group into the classic env grp, err := getgrnam("sudo") if err != nil { return fmt.Errorf("failed to get group info for the 'sudo' group: %s", err) } for _, sudoUser := range grp.Mem { // We need to use "runInClassicEnv" so that we get the // bind mount of the /var/lib/extrausers directory. // Without that the "SUDO_USER" will not exist in the chroot if err := runInClassicEnv("usermod", "-a", "-G", "sudo", sudoUser); err != nil { return fmt.Errorf("failed to add %s to the sudo users: %s", sudoUser, err) } } return nil }