From 9dfb96a954f426b41ad6440f351c056913bb8ea1 Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Wed, 18 Jul 2018 15:34:53 -0700 Subject: [PATCH] Add --device support for Windows Adds support for --device in Windows. This must take the form of: --device='class/{clsid}' Signed-off-by: Justin Terry (VM) --- cli/command/container/opts.go | 104 ----------------------- cli/command/container/opts_unix.go | 115 ++++++++++++++++++++++++++ cli/command/container/opts_windows.go | 33 ++++++++ 3 files changed, 148 insertions(+), 104 deletions(-) create mode 100644 cli/command/container/opts_unix.go create mode 100644 cli/command/container/opts_windows.go diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index 97906b672252..2714e1293156 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "path" "regexp" "strconv" "strings" @@ -742,41 +741,6 @@ func parseStorageOpts(storageOpts []string) (map[string]string, error) { return m, nil } -// parseDevice parses a device mapping string to a container.DeviceMapping struct -func parseDevice(device string) (container.DeviceMapping, error) { - src := "" - dst := "" - permissions := "rwm" - arr := strings.Split(device, ":") - switch len(arr) { - case 3: - permissions = arr[2] - fallthrough - case 2: - if validDeviceMode(arr[1]) { - permissions = arr[1] - } else { - dst = arr[1] - } - fallthrough - case 1: - src = arr[0] - default: - return container.DeviceMapping{}, errors.Errorf("invalid device specification: %s", device) - } - - if dst == "" { - dst = src - } - - deviceMapping := container.DeviceMapping{ - PathOnHost: src, - PathInContainer: dst, - CgroupPermissions: permissions, - } - return deviceMapping, nil -} - // validateDeviceCgroupRule validates a device cgroup rule string format // It will make sure 'val' is in the form: // 'type major:minor mode' @@ -788,74 +752,6 @@ func validateDeviceCgroupRule(val string) (string, error) { return val, errors.Errorf("invalid device cgroup format '%s'", val) } -// validDeviceMode checks if the mode for device is valid or not. -// Valid mode is a composition of r (read), w (write), and m (mknod). -func validDeviceMode(mode string) bool { - var legalDeviceMode = map[rune]bool{ - 'r': true, - 'w': true, - 'm': true, - } - if mode == "" { - return false - } - for _, c := range mode { - if !legalDeviceMode[c] { - return false - } - legalDeviceMode[c] = false - } - return true -} - -// validateDevice validates a path for devices -// It will make sure 'val' is in the form: -// [host-dir:]container-path[:mode] -// It also validates the device mode. -func validateDevice(val string) (string, error) { - return validatePath(val, validDeviceMode) -} - -func validatePath(val string, validator func(string) bool) (string, error) { - var containerPath string - var mode string - - if strings.Count(val, ":") > 2 { - return val, errors.Errorf("bad format for path: %s", val) - } - - split := strings.SplitN(val, ":", 3) - if split[0] == "" { - return val, errors.Errorf("bad format for path: %s", val) - } - switch len(split) { - case 1: - containerPath = split[0] - val = path.Clean(containerPath) - case 2: - if isValid := validator(split[1]); isValid { - containerPath = split[0] - mode = split[1] - val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode) - } else { - containerPath = split[1] - val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath)) - } - case 3: - containerPath = split[1] - mode = split[2] - if isValid := validator(split[2]); !isValid { - return val, errors.Errorf("bad mode specified: %s", mode) - } - val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode) - } - - if !path.IsAbs(containerPath) { - return val, errors.Errorf("%s is not an absolute path", containerPath) - } - return val, nil -} - // validateAttach validates that the specified string is a valid attach option. func validateAttach(val string) (string, error) { s := strings.ToLower(val) diff --git a/cli/command/container/opts_unix.go b/cli/command/container/opts_unix.go new file mode 100644 index 000000000000..561b04a513fb --- /dev/null +++ b/cli/command/container/opts_unix.go @@ -0,0 +1,115 @@ +// +build !windows + +package container + +import ( + "fmt" + "path" + "strings" + + "github.com/docker/docker/api/types/container" + "github.com/pkg/errors" +) + +// parseDevice parses a device mapping string to a container.DeviceMapping struct +func parseDevice(device string) (container.DeviceMapping, error) { + src := "" + dst := "" + permissions := "rwm" + arr := strings.Split(device, ":") + switch len(arr) { + case 3: + permissions = arr[2] + fallthrough + case 2: + if validDeviceMode(arr[1]) { + permissions = arr[1] + } else { + dst = arr[1] + } + fallthrough + case 1: + src = arr[0] + default: + return container.DeviceMapping{}, errors.Errorf("invalid device specification: %s", device) + } + + if dst == "" { + dst = src + } + + deviceMapping := container.DeviceMapping{ + PathOnHost: src, + PathInContainer: dst, + CgroupPermissions: permissions, + } + return deviceMapping, nil +} + +// validDeviceMode checks if the mode for device is valid or not. +// Valid mode is a composition of r (read), w (write), and m (mknod). +func validDeviceMode(mode string) bool { + var legalDeviceMode = map[rune]bool{ + 'r': true, + 'w': true, + 'm': true, + } + if mode == "" { + return false + } + for _, c := range mode { + if !legalDeviceMode[c] { + return false + } + legalDeviceMode[c] = false + } + return true +} + +// validateDevice validates a path for devices +// It will make sure 'val' is in the form: +// [host-dir:]container-path[:mode] +// It also validates the device mode. +func validateDevice(val string) (string, error) { + return validatePath(val, validDeviceMode) +} + +func validatePath(val string, validator func(string) bool) (string, error) { + var containerPath string + var mode string + + if strings.Count(val, ":") > 2 { + return val, errors.Errorf("bad format for path: %s", val) + } + + split := strings.SplitN(val, ":", 3) + if split[0] == "" { + return val, errors.Errorf("bad format for path: %s", val) + } + switch len(split) { + case 1: + containerPath = split[0] + val = path.Clean(containerPath) + case 2: + if isValid := validator(split[1]); isValid { + containerPath = split[0] + mode = split[1] + val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode) + } else { + containerPath = split[1] + val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath)) + } + case 3: + containerPath = split[1] + mode = split[2] + if isValid := validator(split[2]); !isValid { + return val, errors.Errorf("bad mode specified: %s", mode) + } + val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode) + } + + if !path.IsAbs(containerPath) { + return val, errors.Errorf("%s is not an absolute path", containerPath) + } + return val, nil +} diff --git a/cli/command/container/opts_windows.go b/cli/command/container/opts_windows.go new file mode 100644 index 000000000000..2f9abb025041 --- /dev/null +++ b/cli/command/container/opts_windows.go @@ -0,0 +1,33 @@ +// +build windows + +package container + +import ( + "strings" + + "github.com/docker/docker/api/types/container" + "github.com/pkg/errors" +) + +// parseDevice parses a device mapping string to a container.DeviceMapping struct +func parseDevice(device string) (container.DeviceMapping, error) { + return container.DeviceMapping{ + PathOnHost: device, + }, nil +} + +// validateDevice validates a path for devices +// It will make sure 'val' is in the form: +// class/{clsid} +func validateDevice(val string) (string, error) { + arr := strings.Split(val, ":") + switch len(arr) { + case 1: + if !strings.HasPrefix(arr[0], "class") { + return "", errors.New("device must have prefix: 'class'") + } + return val, nil + } + + return "", errors.Errorf("device must be in the format 'class/{clsid}'") +}