Beispiel #1
0
func deviceMountDisk(srcPath string, dstPath string, readonly bool) error {
	var err error

	// Prepare the mount flags
	flags := 0
	if readonly {
		flags |= syscall.MS_RDONLY
	}

	// Detect the filesystem
	fstype := "none"
	if deviceIsDevice(srcPath) {
		fstype, err = shared.BlockFsDetect(srcPath)
		if err != nil {
			return err
		}
	} else {
		flags |= syscall.MS_BIND
	}

	// Mount the filesystem
	if err = syscall.Mount(srcPath, dstPath, fstype, uintptr(flags), ""); err != nil {
		return fmt.Errorf("Unable to mount %s at %s: %s", srcPath, dstPath, err)
	}

	return nil
}
Beispiel #2
0
func deviceToLxc(d shared.Device) ([][]string, error) {
	switch d["type"] {
	case "unix-char":
		return nil, fmt.Errorf("Not implemented")
	case "unix-block":
		return nil, fmt.Errorf("Not implemented")
	case "nic":
		if d["nictype"] != "bridged" && d["nictype"] != "" {
			return nil, fmt.Errorf("Bad nic type: %s\n", d["nictype"])
		}
		var l1 = []string{"lxc.network.type", "veth"}
		var lines = [][]string{l1}
		var l2 []string
		if d["hwaddr"] != "" {
			l2 = []string{"lxc.network.hwaddr", d["hwaddr"]}
			lines = append(lines, l2)
		}
		if d["mtu"] != "" {
			l2 = []string{"lxc.network.mtu", d["mtu"]}
			lines = append(lines, l2)
		}
		if d["parent"] != "" {
			l2 = []string{"lxc.network.link", d["parent"]}
			lines = append(lines, l2)
		}
		if d["name"] != "" {
			l2 = []string{"lxc.network.name", d["name"]}
			lines = append(lines, l2)
		}
		return lines, nil
	case "disk":
		var p string
		configLines := [][]string{}
		if d["path"] == "/" || d["path"] == "" {
			p = ""
		} else if d["path"][0:1] == "/" {
			p = d["path"][1:]
		} else {
			p = d["path"]
		}
		/* TODO - check whether source is a disk, loopback, btrfs subvol, etc */
		/* for now we only handle directory bind mounts */
		source := d["source"]
		fstype := "none"
		options := []string{}
		var err error
		if shared.IsBlockdevPath(d["source"]) {
			fstype, err = shared.BlockFsDetect(d["source"])
			if err != nil {
				return nil, fmt.Errorf("Error setting up %s: %s\n", d["name"], err)
			}
			l, err := addBlockDev(d["source"])
			if err != nil {
				return nil, fmt.Errorf("Error adding blockdev: %s\n", err)
			}
			configLines = append(configLines, l)
		} else if shared.IsDir(source) {
			options = append(options, "bind")
			options = append(options, "create=dir")
		} else /* file bind mount */ {
			/* Todo - can we distinguish between file bind mount and
			 * a qcow2 (or other fs container) file? */
			options = append(options, "bind")
			options = append(options, "create=file")
		}
		if d["readonly"] == "1" || d["readonly"] == "true" {
			options = append(options, "ro")
		}
		if d["optional"] == "1" || d["optional"] == "true" {
			options = append(options, "optional")
		}
		opts := strings.Join(options, ",")
		if opts == "" {
			opts = "defaults"
		}
		l := []string{"lxc.mount.entry", fmt.Sprintf("%s %s %s %s 0 0", source, p, fstype, opts)}
		configLines = append(configLines, l)
		return configLines, nil
	case "none":
		return nil, nil
	default:
		return nil, fmt.Errorf("Bad device type")
	}
}
Beispiel #3
0
func (c *containerLXD) AttachMount(m shared.Device) error {
	dest := m["path"]
	source := m["source"]

	opts := ""
	fstype := "none"
	flags := 0
	sb, err := os.Stat(source)
	if err != nil {
		return err
	}
	if sb.IsDir() {
		flags |= syscall.MS_BIND
		opts = "bind,create=dir"
	} else {
		if !shared.IsBlockdev(sb.Mode()) {
			// Not sure if we want to try dealing with loopdevs, but
			// since we'd need to deal with partitions i think not.
			// We also might want to support file bind mounting, but
			// this doesn't do that.
			return fmt.Errorf("non-block device file not supported\n")
		}

		fstype, err = shared.BlockFsDetect(source)
		if err != nil {
			return fmt.Errorf("Unable to detect fstype for %s: %s\n", source, err)
		}
	}

	// add a lxc.mount.entry = souce destination, in case of reboot
	if m["readonly"] == "1" || m["readonly"] == "true" {
		if opts == "" {
			opts = "ro"
		} else {
			opts = opts + ",ro"
		}
	}
	optional := false
	if m["optional"] == "1" || m["optional"] == "true" {
		optional = true
		opts = opts + ",optional"
	}

	entry := fmt.Sprintf("%s %s %s %s 0 0", source, dest, fstype, opts)
	if err := c.c.SetConfigItem("lxc.mount.entry", entry); err != nil {
		return err
	}

	pid := c.c.InitPid()
	if pid == -1 { // container not running - we're done
		return nil
	}

	// now live-mount
	tmpMount, err := ioutil.TempDir(shared.VarPath("shmounts", c.name), "lxdmount_")
	if err != nil {
		return err
	}

	err = syscall.Mount(m["source"], tmpMount, fstype, uintptr(flags), "")
	if err != nil {
		return err
	}

	mntsrc := filepath.Join("/.lxdmounts", filepath.Base(tmpMount))
	// finally we need to move-mount this in the container
	pidstr := fmt.Sprintf("%d", pid)
	err = exec.Command(os.Args[0], "forkmount", pidstr, mntsrc, m["path"]).Run()
	syscall.Unmount(tmpMount, syscall.MNT_DETACH) // in case forkmount failed
	os.Remove(tmpMount)

	if err != nil && !optional {
		return err
	}
	return nil
}