@@ -141,7 +141,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
141141 deviceReadIOps : opts .NewThrottledeviceOpt (opts .ValidateThrottleIOpsDevice ),
142142 deviceWriteBps : opts .NewThrottledeviceOpt (opts .ValidateThrottleBpsDevice ),
143143 deviceWriteIOps : opts .NewThrottledeviceOpt (opts .ValidateThrottleIOpsDevice ),
144- devices : opts .NewListOpts (validateDevice ),
144+ devices : opts .NewListOpts (nil ), // devices can only be validated after we know the server OS
145145 env : opts .NewListOpts (opts .ValidateEnv ),
146146 envFile : opts .NewListOpts (nil ),
147147 expose : opts .NewListOpts (nil ),
@@ -299,7 +299,7 @@ type containerConfig struct {
299299// a HostConfig and returns them with the specified command.
300300// If the specified args are not valid, it will return an error.
301301// nolint: gocyclo
302- func parse (flags * pflag.FlagSet , copts * containerOptions ) (* containerConfig , error ) {
302+ func parse (flags * pflag.FlagSet , copts * containerOptions , serverOS string ) (* containerConfig , error ) {
303303 var (
304304 attachStdin = copts .attach .Get ("stdin" )
305305 attachStdout = copts .attach .Get ("stdout" )
@@ -417,10 +417,22 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
417417 }
418418 }
419419
420- // parse device mappings
420+ // validate and parse device mappings. Note we do late validation of the
421+ // device path (as opposed to during flag parsing), as at the time we are
422+ // parsing flags, we haven't yet sent a _ping to the daemon to determine
423+ // what operating system it is.
421424 deviceMappings := []container.DeviceMapping {}
422425 for _ , device := range copts .devices .GetAll () {
423- deviceMapping , err := parseDevice (device )
426+ var (
427+ validated string
428+ deviceMapping container.DeviceMapping
429+ err error
430+ )
431+ validated , err = validateDevice (device , serverOS )
432+ if err != nil {
433+ return nil , err
434+ }
435+ deviceMapping , err = parseDevice (validated , serverOS )
424436 if err != nil {
425437 return nil , err
426438 }
@@ -747,7 +759,19 @@ func parseStorageOpts(storageOpts []string) (map[string]string, error) {
747759}
748760
749761// parseDevice parses a device mapping string to a container.DeviceMapping struct
750- func parseDevice (device string ) (container.DeviceMapping , error ) {
762+ func parseDevice (device , serverOS string ) (container.DeviceMapping , error ) {
763+ switch serverOS {
764+ case "linux" :
765+ return parseLinuxDevice (device )
766+ case "windows" :
767+ return parseWindowsDevice (device )
768+ }
769+ return container.DeviceMapping {}, errors .Errorf ("unknown server OS: %s" , serverOS )
770+ }
771+
772+ // parseLinuxDevice parses a device mapping string to a container.DeviceMapping struct
773+ // knowing that the target is a Linux daemon
774+ func parseLinuxDevice (device string ) (container.DeviceMapping , error ) {
751775 src := ""
752776 dst := ""
753777 permissions := "rwm"
@@ -781,6 +805,12 @@ func parseDevice(device string) (container.DeviceMapping, error) {
781805 return deviceMapping , nil
782806}
783807
808+ // parseWindowsDevice parses a device mapping string to a container.DeviceMapping struct
809+ // knowing that the target is a Windows daemon
810+ func parseWindowsDevice (device string ) (container.DeviceMapping , error ) {
811+ return container.DeviceMapping {PathOnHost : device }, nil
812+ }
813+
784814// validateDeviceCgroupRule validates a device cgroup rule string format
785815// It will make sure 'val' is in the form:
786816// 'type major:minor mode'
@@ -813,14 +843,23 @@ func validDeviceMode(mode string) bool {
813843}
814844
815845// validateDevice validates a path for devices
846+ func validateDevice (val string , serverOS string ) (string , error ) {
847+ switch serverOS {
848+ case "linux" :
849+ return validateLinuxPath (val , validDeviceMode )
850+ case "windows" :
851+ // Windows does validation entirely server-side
852+ return val , nil
853+ }
854+ return "" , errors .Errorf ("unknown server OS: %s" , serverOS )
855+ }
856+
857+ // validateLinuxPath is the implementation of validateDevice knowing that the
858+ // target server operating system is a Linux daemon.
816859// It will make sure 'val' is in the form:
817860// [host-dir:]container-path[:mode]
818861// It also validates the device mode.
819- func validateDevice (val string ) (string , error ) {
820- return validatePath (val , validDeviceMode )
821- }
822-
823- func validatePath (val string , validator func (string ) bool ) (string , error ) {
862+ func validateLinuxPath (val string , validator func (string ) bool ) (string , error ) {
824863 var containerPath string
825864 var mode string
826865
0 commit comments