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 }
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") } }
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 }