lxd/container_lxc.go
func (c *containerLXC) createUnixDevice(prefix string, m types.Device, defaultMode bool) ([]string, error) {
	var err error
	var major, minor int

	// Extra checks for nesting
	if c.state.OS.RunningInUserNS {
		for key, value := range m {
			if shared.StringInSlice(key, []string{"major", "minor", "mode", "uid", "gid"}) && value != "" {
				return nil, fmt.Errorf("The \"%s\" property may not be set when adding a device to a nested container", key)
			}
		}
	}

	srcPath := m["source"]
	if srcPath == "" {
		srcPath = m["path"]
	}
	srcPath = shared.HostPath(srcPath)

	// Get the major/minor of the device we want to create
	if m["major"] == "" && m["minor"] == "" {
		// If no major and minor are set, use those from the device on the host
		_, major, minor, err = deviceGetAttributes(srcPath)
		if err != nil {
			return nil, fmt.Errorf("Failed to get device attributes for %s: %s", m["path"], err)
		}
	} else if m["major"] == "" || m["minor"] == "" {
		return nil, fmt.Errorf("Both major and minor must be supplied for device: %s", m["path"])
	} else {
		major, err = strconv.Atoi(m["major"])
		if err != nil {
			return nil, fmt.Errorf("Bad major %s in device %s", m["major"], m["path"])
		}

		minor, err = strconv.Atoi(m["minor"])
		if err != nil {
			return nil, fmt.Errorf("Bad minor %s in device %s", m["minor"], m["path"])
		}
	}

	// Get the device mode
	mode := os.FileMode(0660)
	if m["mode"] != "" {
		tmp, err := deviceModeOct(m["mode"])
		if err != nil {
			return nil, fmt.Errorf("Bad mode %s in device %s", m["mode"], m["path"])
		}
		mode = os.FileMode(tmp)
	} else if !defaultMode {
		mode, err = shared.GetPathMode(srcPath)
		if err != nil {
			errno, isErrno := shared.GetErrno(err)
			if !isErrno || errno != syscall.ENOENT {
				return nil, fmt.Errorf("Failed to retrieve mode of device %s: %s", m["path"], err)
			}
			mode = os.FileMode(0660)
		}
	}

	if m["type"] == "unix-block" {
		mode |= syscall.S_IFBLK
	} else {
		mode |= syscall.S_IFCHR
	}

	// Get the device owner
	uid := 0
	gid := 0

	if m["uid"] != "" {
		uid, err = strconv.Atoi(m["uid"])
		if err != nil {
			return nil, fmt.Errorf("Invalid uid %s in device %s", m["uid"], m["path"])
		}
	}

	if m["gid"] != "" {
		gid, err = strconv.Atoi(m["gid"])
		if err != nil {
			return nil, fmt.Errorf("Invalid gid %s in device %s", m["gid"], m["path"])
		}
	}

	// Create the devices directory if missing
	if !shared.PathExists(c.DevicesPath()) {
		os.Mkdir(c.DevicesPath(), 0711)
		if err != nil {
			return nil, fmt.Errorf("Failed to create devices path: %s", err)
		}
	}

	destPath := m["path"]
	if destPath == "" {
		destPath = m["source"]
	}
	relativeDestPath := strings.TrimPrefix(destPath, "/")
	devName := fmt.Sprintf("%s.%s", strings.Replace(prefix, "/", "-", -1), strings.Replace(relativeDestPath, "/", "-", -1))
	devPath := filepath.Join(c.DevicesPath(), devName)

	// Create the new entry
	if !c.state.OS.RunningInUserNS {
		encoded_device_number := (minor & 0xff) | (major << 8) | ((minor & ^0xff) << 12)
		if err := syscall.Mknod(devPath, uint32(mode), encoded_device_number); err != nil {
			return nil, fmt.Errorf("Failed to create device %s for %s: %s", devPath, m["path"], err)
		}

		if err := os.Chown(devPath, uid, gid); err != nil {
			return nil, fmt.Errorf("Failed to chown device %s: %s", devPath, err)
		}

		// Needed as mknod respects the umask
		if err := os.Chmod(devPath, mode); err != nil {
			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPath, err)
		}

		idmapset, err := c.CurrentIdmap()
		if err != nil {
			return nil, err
		}

		if idmapset != nil {
			if err := idmapset.ShiftFile(devPath); err != nil {
				// uidshift failing is weird, but not a big problem.  Log and proceed
				logger.Debugf("Failed to uidshift device %s: %s\n", m["path"], err)
			}
		}
	} else {
		f, err := os.Create(devPath)
		if err != nil {
			return nil, err
		}
		f.Close()

		err = deviceMountDisk(srcPath, devPath, false, false, "")
		if err != nil {
			return nil, err
		}
	}

	return []string{devPath, relativeDestPath}, nil
}
func (c *containerLXC) createUnixDevice(prefix string, m types.Device, defaultMode bool) ([]string, error) {
	var err error
	var major, minor int

	// Extra checks for nesting
	if c.state.OS.RunningInUserNS {
		for key, value := range m {
			if shared.StringInSlice(key, []string{"major", "minor", "mode", "uid", "gid"}) && value != "" {
				return nil, fmt.Errorf("The \"%s\" property may not be set when adding a device to a nested container", key)
			}
		}
	}

	srcPath := m["source"]
	if srcPath == "" {
		srcPath = m["path"]
	}
	srcPath = shared.HostPath(srcPath)

	// Get the major/minor of the device we want to create
	if m["major"] == "" && m["minor"] == "" {
		// If no major and minor are set, use those from the device on the host
		_, major, minor, err = deviceGetAttributes(srcPath)
		if err != nil {
			return nil, fmt.Errorf("Failed to get device attributes for %s: %s", m["path"], err)
		}
	} else if m["major"] == "" || m["minor"] == "" {
		return nil, fmt.Errorf("Both major and minor must be supplied for device: %s", m["path"])
	} else {
		major, err = strconv.Atoi(m["major"])
		if err != nil {
			return nil, fmt.Errorf("Bad major %s in device %s", m["major"], m["path"])
		}

		minor, err = strconv.Atoi(m["minor"])
		if err != nil {
			return nil, fmt.Errorf("Bad minor %s in device %s", m["minor"], m["path"])
		}
	}

	// Get the device mode
	mode := os.FileMode(0660)
	if m["mode"] != "" {
		tmp, err := deviceModeOct(m["mode"])
		if err != nil {
			return nil, fmt.Errorf("Bad mode %s in device %s", m["mode"], m["path"])
		}
		mode = os.FileMode(tmp)
	} else if !defaultMode {
		mode, err = shared.GetPathMode(srcPath)
		if err != nil {
			errno, isErrno := shared.GetErrno(err)
			if !isErrno || errno != syscall.ENOENT {
				return nil, fmt.Errorf("Failed to retrieve mode of device %s: %s", m["path"], err)
			}
			mode = os.FileMode(0660)
		}
	}

	if m["type"] == "unix-block" {
		mode |= syscall.S_IFBLK
	} else {
		mode |= syscall.S_IFCHR
	}

	// Get the device owner
	uid := 0
	gid := 0

	if m["uid"] != "" {
		uid, err = strconv.Atoi(m["uid"])
		if err != nil {
			return nil, fmt.Errorf("Invalid uid %s in device %s", m["uid"], m["path"])
		}
	}

	if m["gid"] != "" {
		gid, err = strconv.Atoi(m["gid"])
		if err != nil {
			return nil, fmt.Errorf("Invalid gid %s in device %s", m["gid"], m["path"])
		}
	}

	// Create the devices directory if missing
	if !shared.PathExists(c.DevicesPath()) {
		os.Mkdir(c.DevicesPath(), 0711)
		if err != nil {
			return nil, fmt.Errorf("Failed to create devices path: %s", err)
		}
	}

	destPath := m["path"]
	if destPath == "" {
		destPath = m["source"]
	}
	relativeDestPath := strings.TrimPrefix(destPath, "/")
	devName := fmt.Sprintf("%s.%s", strings.Replace(prefix, "/", "-", -1), strings.Replace(relativeDestPath, "/", "-", -1))
	devPath := filepath.Join(c.DevicesPath(), devName)

	// Create the new entry
	if !c.state.OS.RunningInUserNS {
		encoded_device_number := (minor & 0xff) | (major << 8) | ((minor & ^0xff) << 12)
		if err := syscall.Mknod(devPath, uint32(mode), encoded_device_number); err != nil {
			return nil, fmt.Errorf("Failed to create device %s for %s: %s", devPath, m["path"], err)
		}

		if err := os.Chown(devPath, uid, gid); err != nil {
			return nil, fmt.Errorf("Failed to chown device %s: %s", devPath, err)
		}

		// Needed as mknod respects the umask
		if err := os.Chmod(devPath, mode); err != nil {
			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPath, err)
		}

		idmapset, err := c.CurrentIdmap()
		if err != nil {
			return nil, err
		}

		if idmapset != nil {
			if err := idmapset.ShiftFile(devPath); err != nil {
				// uidshift failing is weird, but not a big problem.  Log and proceed
				logger.Debugf("Failed to uidshift device %s: %s\n", m["path"], err)
			}
		}
	} else {
		f, err := os.Create(devPath)
		if err != nil {
			return nil, err
		}
		f.Close()

		err = deviceMountDisk(srcPath, devPath, false, false, "")
		if err != nil {
			return nil, err
		}
	}

	return []string{devPath, relativeDestPath}, nil
}
func ( c * containerLXC ) createUnixDevice ( prefix string , m types . Device , defaultMode bool ) ( [ ] string , error ) { var err error var major , minor int // Extra checks for nesting if c . state . OS . RunningInUserNS { for key , value := range m { if shared . StringInSlice ( key , [ ] string { " " , " " , " " , " " , " " } ) && value != " " { return nil , fmt . Errorf ( " \" \" " , key ) } } } srcPath := m [ " " ] if srcPath == " " { srcPath = m [ " " ] } srcPath = shared . HostPath ( srcPath ) // Get the major/minor of the device we want to create if m [ " " ] == " " && m [ " " ] == " " { // If no major and minor are set, use those from the device on the host _ , major , minor , err = deviceGetAttributes ( srcPath ) if err != nil { return nil , fmt . Errorf ( " " , m [ " " ] , err ) } } else if m [ " " ] == " " || m [ " " ] == " " { return nil , fmt . Errorf ( " " , m [ " " ] ) } else { major , err = strconv . Atoi ( m [ " " ] ) if err != nil { return nil , fmt . Errorf ( " " , m [ " " ] , m [ " " ] ) } minor , err = strconv . Atoi ( m [ " " ] ) if err != nil { return nil , fmt . Errorf ( " " , m [ " " ] , m [ " " ] ) } } // Get the device mode mode := os . FileMode ( 0660 ) if m [ " " ] != " " { tmp , err := deviceModeOct ( m [ " " ] ) if err != nil { return nil , fmt . Errorf ( " " , m [ " " ] , m [ " " ] ) } mode = os . FileMode ( tmp ) } else if ! defaultMode { mode , err = shared . GetPathMode ( srcPath ) if err != nil { errno , isErrno := shared . GetErrno ( err ) if ! isErrno || errno != syscall . ENOENT { return nil , fmt . Errorf ( " " , m [ " " ] , err ) } mode = os . FileMode ( 0660 ) } } if m [ " " ] == " " { mode |= syscall . S_IFBLK } else { mode |= syscall . S_IFCHR } // Get the device owner uid := 0 gid := 0 if m [ " " ] != " " { uid , err = strconv . Atoi ( m [ " " ] ) if err != nil { return nil , fmt . Errorf ( " " , m [ " " ] , m [ " " ] ) } } if m [ " " ] != " " { gid , err = strconv . Atoi ( m [ " " ] ) if err != nil { return nil , fmt . Errorf ( " " , m [ " " ] , m [ " " ] ) } } // Create the devices directory if missing if ! shared . PathExists ( c . DevicesPath ( ) ) { os . Mkdir ( c . DevicesPath ( ) , 0711 ) if err != nil { return nil , fmt . Errorf ( " " , err ) } } destPath := m [ " " ] if destPath == " " { destPath = m [ " " ] } relativeDestPath := strings . TrimPrefix ( destPath , " " ) devName := fmt . Sprintf ( " " , strings . Replace ( prefix , " " , " " , - 1 ) , strings . Replace ( relativeDestPath , " " , " " , - 1 ) ) devPath := filepath . Join ( c . DevicesPath ( ) , devName ) // Create the new entry if ! c . state . OS . RunningInUserNS { encoded_device_number := ( minor & 0xff ) | ( major << 8 ) | ( ( minor & ^ 0xff ) << 12 ) if err := syscall . Mknod ( devPath , uint32 ( mode ) , encoded_device_number ) ; err != nil { return nil , fmt . Errorf ( " " , devPath , m [ " " ] , err ) } if err := os . Chown ( devPath , uid , gid ) ; err != nil { return nil , fmt . Errorf ( " " , devPath , err ) } // Needed as mknod respects the umask if err := os . Chmod ( devPath , mode ) ; err != nil { return nil , fmt . Errorf ( " " , devPath , err ) } idmapset , err := c . CurrentIdmap ( ) if err != nil { return nil , err } if idmapset != nil { if err := idmapset . ShiftFile ( devPath ) ; err != nil { // uidshift failing is weird, but not a big problem.  Log and proceed logger . Debugf ( " \n " , m [ " " ] , err ) } } } else { f , err := os . Create ( devPath ) if err != nil { return nil , err } f . Close ( ) err = deviceMountDisk ( srcPath , devPath , false , false , " " ) if err != nil { return nil , err } } return [ ] string { devPath , relativeDestPath } , nil }
// Unix devices handling
Unix devices handling