// Buildqcow2 creates a qcow2 image using qemu-img, qemu-nbd, fdisk, mkfs.ext4, // cp, and extlinux. func Buildqcow2(buildPath string, c vmconfig.Config) error { targetName := strings.Split(filepath.Base(c.Path), ".")[0] log.Debugln("using target name:", targetName) err := nbd.Modprobe() if err != nil { return err } wd, err := os.Getwd() if err != nil { return err } // Final qcow2 target targetqcow2 := fmt.Sprintf("%v/%v.qcow2", wd, targetName) // Temporary file for building qcow2 file, will be renamed to targetqcow2 tmpqcow2 := fmt.Sprintf("%v/%v.qcow2.tmp", wd, targetName) err = createQcow2(tmpqcow2, *f_qcowsize) if err != nil { return err } // Cleanup our temporary building file defer func() { // Check if file exists if _, err := os.Stat(tmpqcow2); err == nil { if err = os.Remove(tmpqcow2); err != nil { log.Errorln(err) } } }() dev, err := nbd.ConnectImage(tmpqcow2) if err != nil { return err } // Disconnect from the nbd device defer func() { if err := nbd.DisconnectDevice(dev); err != nil { log.Errorln(err) } }() err = partitionQcow2(dev) if err != nil { return err } err = formatQcow2(dev + "p1") if err != nil { return err } mountPath, err := mountQcow2(dev + "p1") if err != nil { return err } err = copyQcow2(buildPath, mountPath) if err != nil { err2 := umountQcow2(mountPath) if err2 != nil { log.Errorln(err2) } return err } err = extlinux(mountPath) if err != nil { err2 := umountQcow2(mountPath) if err2 != nil { log.Errorln(err2) } return err } err = umountQcow2(mountPath) if err != nil { return err } err = extlinuxMBR(dev, *f_mbr) if err != nil { return err } return os.Rename(tmpqcow2, targetqcow2) }
func (inject *injectData) run() (string, error) { if inject.err != nil { return "", inject.err } // create the new img p := process("qemu-img") cmd := exec.Command(p, "create", "-f", "qcow2", "-b", inject.srcImg, inject.dstImg) log.Debug("creating sub image with: %v", cmd) result, err := cmd.CombinedOutput() if err != nil { return "", fmt.Errorf("%v\n%v", string(result[:]), err) } // create a tmp mount point mntDir, err := ioutil.TempDir(*f_base, "dstImg") if err != nil { return "", err } log.Debug("temporary mount point: %v", mntDir) inject.nbdPath, err = nbd.ConnectImage(inject.dstImg) if err != nil { return "", err } defer vmInjectCleanup(mntDir, inject.nbdPath) time.Sleep(100 * time.Millisecond) // give time to create partitions // decide on a partition if inject.partition == "" { _, err = os.Stat(inject.nbdPath + "p1") if err != nil { return "", errors.New("no partitions found") } _, err = os.Stat(inject.nbdPath + "p2") if err == nil { return "", errors.New("please specify a partition; multiple found") } inject.partition = "1" } // mount new img p = process("mount") cmd = exec.Command(p, "-w", inject.nbdPath+"p"+inject.partition, mntDir) result, err = cmd.CombinedOutput() if err != nil { // check that ntfs-3g is installed p = process("ntfs-3g") cmd = exec.Command(p, "--version") _, err = cmd.CombinedOutput() if err != nil { log.Error("ntfs-3g not found, ntfs images unwriteable") } // mount with ntfs-3g p = process("mount") cmd = exec.Command(p, "-o", "ntfs-3g", inject.nbdPath+"p"+inject.partition, mntDir) result, err = cmd.CombinedOutput() if err != nil { log.Error("failed to mount partition") return "", fmt.Errorf("%v\n%v", string(result[:]), err) } } // copy files/folders into mntDir p = process("cp") for _, pair := range inject.pairs { dir := filepath.Dir(filepath.Join(mntDir, pair.dst)) os.MkdirAll(dir, 0775) cmd = exec.Command(p, "-fr", pair.src, mntDir+"/"+pair.dst) result, err = cmd.CombinedOutput() if err != nil { return "", fmt.Errorf("%v\n%v", string(result[:]), err) } } return inject.dstImg, nil }
// diskInject injects files into a disk image. dst/partition specify the image // and the partition number, pairs is the dst, src filepaths. options can be // used to supply mount arguments. func diskInject(dst, partition string, pairs map[string]string, options []string) error { // Load nbd if err := nbd.Modprobe(); err != nil { return err } // create a tmp mount point mntDir, err := ioutil.TempDir(*f_base, "dstImg") if err != nil { return err } log.Debug("temporary mount point: %v", mntDir) nbdPath, err := nbd.ConnectImage(dst) if err != nil { return err } defer diskInjectCleanup(mntDir, nbdPath) time.Sleep(100 * time.Millisecond) // give time to create partitions // decide on a partition if partition == "" { _, err = os.Stat(nbdPath + "p1") if err != nil { return errors.New("no partitions found") } _, err = os.Stat(nbdPath + "p2") if err == nil { return errors.New("please specify a partition; multiple found") } partition = "1" } // mount new img var path string if partition == "none" { path = nbdPath } else { path = nbdPath + "p" + partition } // we use mount(8), because the mount syscall (mount(2)) requires we // populate the fstype field, which we don't know args := []string{"mount"} if len(options) != 0 { args = append(args, options...) args = append(args, path, mntDir) } else { args = []string{"mount", "-w", path, mntDir} } log.Debug("mount args: %v", args) _, err = processWrapper(args...) if err != nil { // check that ntfs-3g is installed _, err = processWrapper("ntfs-3g", "--version") if err != nil { log.Error("ntfs-3g not found, ntfs images unwriteable") } // mount with ntfs-3g out, err := processWrapper("mount", "-o", "ntfs-3g", path, mntDir) if err != nil { log.Error("failed to mount partition") return fmt.Errorf("%v: %v", out, err) } } // copy files/folders into mntDir for dst, src := range pairs { dir := filepath.Dir(filepath.Join(mntDir, dst)) os.MkdirAll(dir, 0775) out, err := processWrapper("cp", "-fr", src, filepath.Join(mntDir, dst)) if err != nil { return fmt.Errorf("%v: %v", out, err) } } return nil }