Class: Vagrant::Util::Platform

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant/util/platform.rb

Overview

This class just contains some platform checking code.

Constant Summary collapse

MOUNT_PATTERN =

Mount pattern for extracting local mount information

/^(?<device>.+?) on (?<mount>.+?) type (?<type>.+?) \((?<options>.+)\)/.freeze

Class Method Summary collapse

Class Method Details

.architectureString

Detect architecture of host system

Returns:

  • (String)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/vagrant/util/platform.rb', line 23

def architecture
  if !defined?(@_host_architecture)
    if ENV["VAGRANT_HOST_ARCHITECTURE"].to_s != ""
      return @_host_architecture = ENV["VAGRANT_HOST_ARCHITECTURE"]
    end

    @_host_architecture = case RbConfig::CONFIG["target_cpu"]
      when "amd64", "x86_64", "x64"
        "amd64"
      when "386", "i386", "x86"
        "i386"
      when "arm64", "aarch64"
        "arm64"
      else
        RbConfig::CONFIG["target_cpu"]
      end
  end
  @_host_architecture
end

.cygwin?Boolean

Returns:

  • (Boolean)


50
51
52
53
54
55
56
57
# File 'lib/vagrant/util/platform.rb', line 50

def cygwin?
  if !defined?(@_cygwin)
    @_cygwin = ENV["VAGRANT_DETECTED_OS"].to_s.downcase.include?("cygwin") ||
      platform.include?("cygwin") ||
      ENV["OSTYPE"].to_s.downcase.include?("cygwin")
  end
  @_cygwin
end

.cygwin_path(path) ⇒ String

This takes any path and converts it from a Windows path to a Cygwin style path.

Parameters:

  • path (String)

Returns:

  • (String)


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/vagrant/util/platform.rb', line 195

def cygwin_path(path)
  begin
    cygpath = Vagrant::Util::Which.which("cygpath")
    if cygpath.nil?
      # If Which can't find it, just attempt to invoke it directly
      cygpath = "cygpath"
    else
      cygpath.gsub!("/", '\\')
    end

    process = Subprocess.execute(
      cygpath, "-u", "-a", path.to_s)
    return process.stdout.chomp
  rescue Errors::CommandUnavailableWindows => e
    # Sometimes cygpath isn't available (msys). Instead, do what we
    # can with bash tricks.
    process = Subprocess.execute(
      "bash",
      "--noprofile",
      "--norc",
      "-c", "cd #{Shellwords.escape(path)} && pwd")
    return process.stdout.chomp
  end
end

.cygwin_windows_path(path) ⇒ String

This takes any path and converts it to a full-length Windows path on Windows machines in Cygwin.

Returns:

  • (String)


244
245
246
247
248
249
250
251
252
253
# File 'lib/vagrant/util/platform.rb', line 244

def cygwin_windows_path(path)
  return path if !cygwin?

  # Replace all "\" with "/", otherwise cygpath doesn't work.
  path = unix_windows_path(path)

  # Call out to cygpath and gather the result
  process = Subprocess.execute("cygpath", "-w", "-l", "-a", path.to_s)
  return process.stdout.chomp
end

.format_windows_path(path, *args) ⇒ String

Takes a windows path and formats it to the 'unix' style (i.e. /cygdrive/c or /c/)

Parameters:

  • path (Pathname, String)

    Path to convert

  • hash (Hash)

    of arguments

Returns:

  • (String)


512
513
514
515
516
517
518
519
520
521
# File 'lib/vagrant/util/platform.rb', line 512

def format_windows_path(path, *args)
  path = cygwin_path(path) if cygwin?
  path = msys_path(path) if msys?
  path = wsl_to_windows_path(path) if wsl?
  if windows? || wsl?
    path = windows_unc_path(path) if !args.include?(:disable_unc)
  end

  path
end

.fs_case_sensitive?Boolean

This checks if the filesystem is case sensitive. This is not a 100% correct check, since it is possible that the temporary directory runs a different filesystem than the root directory. However, this works in many cases.

Returns:

  • (Boolean)


266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/vagrant/util/platform.rb', line 266

def fs_case_sensitive?
  return @_fs_case_sensitive if defined?(@_fs_case_sensitive)
  @_fs_case_sensitive = Dir.mktmpdir("vagrant-fs-case-sensitive") do |dir|
    tmp_file = File.join(dir, "FILE")
    File.open(tmp_file, "w") do |f|
      f.write("foo")
    end

    # The filesystem is case sensitive if the lowercased version
    # of the filename is NOT reported as existing.
    !File.file?(File.join(dir, "file"))
  end
  return @_fs_case_sensitive
end

.fs_real_path(path, **opts) ⇒ Object

This expands the path and ensures proper casing of each part of the path.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/vagrant/util/platform.rb', line 283

def fs_real_path(path, **opts)
  path = Pathname.new(File.expand_path(path))

  if path.exist? && !fs_case_sensitive?
    # If the path contains a Windows short path, then we attempt to
    # expand. The require below is embedded here since it requires
    # windows to work.
    if windows? && path.to_s =~ /~\d(\/|\\)/
      require_relative "windows_path"
      path = Pathname.new(WindowsPath.longname(path.to_s))
    end

    # Build up all the parts of the path
    original = []
    while !path.root?
      original.unshift(path.basename.to_s)
      path = path.parent
    end

    # Traverse each part and join it into the resulting path
    original.each do |single|
      Dir.entries(path).each do |entry|
        begin
          single = single.encode("filesystem").to_s
        rescue ArgumentError => err
          Vagrant.global_logger.warn("path encoding failed - part=#{single} err=#{err.class} msg=#{err}")
          # NOTE: Depending on the Windows environment the above
          # encode will generate an "input string invalid" when
          # attempting to encode. If that happens, continue on
        end
        if entry.downcase == single.downcase
          path = path.join(entry)
        end
      end
    end
  end

  if windows?
    # Fix the drive letter to be uppercase.
    path = path.to_s
    if path[1] == ":"
      path[0] = path[0].upcase
    end

    path = Pathname.new(path)
  end

  path
end

.loggerObject



43
44
45
46
47
48
# File 'lib/vagrant/util/platform.rb', line 43

def logger
  if !defined?(@_logger)
    @_logger = Log4r::Logger.new("vagrant::util::platform")
  end
  @_logger
end

.msys?Boolean

Returns:

  • (Boolean)


59
60
61
62
63
64
65
66
# File 'lib/vagrant/util/platform.rb', line 59

def msys?
  if !defined?(@_msys)
    @_msys = ENV["VAGRANT_DETECTED_OS"].to_s.downcase.include?("msys") ||
      platform.include?("msys") ||
      ENV["OSTYPE"].to_s.downcase.include?("msys")
  end
  @_msys
end

.msys_path(path) ⇒ String

This takes any path and converts it from a Windows path to a msys style path.

Parameters:

  • path (String)

Returns:

  • (String)


225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/vagrant/util/platform.rb', line 225

def msys_path(path)
  begin
    # We have to revert to the old env
    # path here, otherwise it looks like
    # msys2 ends up using the wrong cygpath
    # binary and ends up with a `/cygdrive`
    # when it doesn't exist in msys2
    original_path_env = ENV['PATH']
    ENV['PATH'] = ENV['VAGRANT_OLD_ENV_PATH']
    cygwin_path(path)
  ensure
    ENV['PATH'] = original_path_env
  end
end

.platformObject



368
369
370
371
372
# File 'lib/vagrant/util/platform.rb', line 368

def platform
  return @_platform if defined?(@_platform)
  @_platform = RbConfig::CONFIG["host_os"].downcase
  return @_platform
end

.reset!Object

Reset the cached values for platform. This is not considered a public API and should only be used for testing.



731
732
733
# File 'lib/vagrant/util/platform.rb', line 731

def reset!
  instance_variables.each(&method(:remove_instance_variable))
end

.systemd?Boolean

systemd is in use

Returns:

  • (Boolean)


716
717
718
719
720
721
722
723
724
725
726
# File 'lib/vagrant/util/platform.rb', line 716

def systemd?
  if !defined?(@_systemd)
    if !windows?
      result = Vagrant::Util::Subprocess.execute("ps", "-o", "comm=", "1")
      @_systemd = result.stdout.chomp == "systemd"
    else
      @_systemd = false
    end
  end
  @_systemd
end

.terminal_supports_colors?Boolean

Returns a boolean noting whether the terminal supports color. output.

Returns:

  • (Boolean)


353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/vagrant/util/platform.rb', line 353

def terminal_supports_colors?
  return @_terminal_supports_colors if defined?(@_terminal_supports_colors)
  @_terminal_supports_colors = -> {
    if windows?
      return true if ENV.key?("ANSICON")
      return true if cygwin?
      return true if ENV["TERM"] == "cygwin"
      return false
    end

    return true
  }.call
  return @_terminal_supports_colors
end

.unix_windows_path(path) ⇒ String

This takes any path and converts Windows-style path separators to Unix-like path separators.

Returns:

  • (String)


258
259
260
# File 'lib/vagrant/util/platform.rb', line 258

def unix_windows_path(path)
  path.gsub("\\", "/")
end

.windows?Boolean

Returns:

  • (Boolean)


90
91
92
93
94
# File 'lib/vagrant/util/platform.rb', line 90

def windows?
  return @_windows if defined?(@_windows)
  @_windows = %w[mingw mswin].any? { |t| platform.include?(t) }
  return @_windows
end

.windows_admin?Boolean

Checks if the user running Vagrant on Windows has administrative privileges.

From: https://support.microsoft.com/en-us/kb/243330 SID: S-1-5-19

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
# File 'lib/vagrant/util/platform.rb', line 103

def windows_admin?
  return @_windows_admin if defined?(@_windows_admin)

  @_windows_admin = -> {
    ps_cmd = '(new-object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)'
    output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
    return output == 'True'
  }.call

  return @_windows_admin
end

.windows_hyperv_admin?Boolean

Checks if Hyper-V is accessible to the local user. It will check if user is in the "Hyper-V Administrators" group, is a Domain administrator, and finally will run a manual interaction with Hyper-V to determine if Hyper-V is usable for the current user.

From: https://support.microsoft.com/en-us/kb/243330 SID: S-1-5-32-578 Name: BUILTIN\Hyper-V Administrators SID: S-1-5-21DOMAIN-512 Name: Domain Admins

Returns:

  • (Boolean)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/vagrant/util/platform.rb', line 127

def windows_hyperv_admin?
  return @_windows_hyperv_admin if defined?(@_windows_hyperv_admin)

  if ENV["VAGRANT_IS_HYPERV_ADMIN"]
    return @_windows_hyperv_admin = true
  end

  ps_cmd = "Write-Output ([System.Security.Principal.WindowsIdentity]::GetCurrent().Groups | " \
    "Select-Object Value | ConvertTo-JSON)"
  output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
  if output
    groups = begin
               JSON.load(output)
             rescue JSON::ParserError
               []
             end
    admin_group = groups.detect do |g|
      g["Value"].to_s == "S-1-5-32-578" ||
        (g["Value"].start_with?("S-1-5-21") && g["Value"].to_s.end_with?("-512"))
    end

    if admin_group
      return @_windows_hyperv_admin = true
    end
  end

  ps_cmd = "$x = (Get-VMHost).Name; if($x -eq [System.Net.Dns]::GetHostName()){ Write-Output 'true'}"
  output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
  result = output == "true"

  return @_windows_hyperv_admin = result
end

.windows_hyperv_enabled?Boolean

Checks if Hyper-V is enabled on the host system and returns true if enabled.

Returns:

  • (Boolean)


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/vagrant/util/platform.rb', line 164

def windows_hyperv_enabled?
  return @_windows_hyperv_enabled if defined?(@_windows_hyperv_enabled)

  @_windows_hyperv_enabled = -> {
    check_commands = Array.new.tap do |c|
      c << "(Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-Hypervisor -Online).State"
      c << "(Get-WindowsFeature -FeatureName Microsoft-Hyper-V-Hypervisor).State"
    end
    check_commands.each do |ps_cmd|
      begin
        output = Vagrant::Util::PowerShell.execute_cmd(ps_cmd)
        return true if output == "Enabled"
      rescue Errors::PowerShellInvalidVersion
        logger.warn("Invalid PowerShell version detected during Hyper-V enable check")
        return false
      rescue Errors::PowerShellError
        logger.warn("Powershell command not found or error on execution of command")
        return false
      end
    end
    return false
  }.call

  return @_windows_hyperv_enabled
end

.windows_path(path) ⇒ String

Automatically convert a given path to a Windows path. Will only be applied if running on a Windows host. If running on Windows host within the WSL, the actual Windows path will be returned.

Parameters:

  • path (Pathname, String)

    Path to convert

Returns:

  • (String)


529
530
531
532
533
534
535
536
# File 'lib/vagrant/util/platform.rb', line 529

def windows_path(path)
  path = cygwin_windows_path(path)
  path = wsl_to_windows_path(path)
  if windows? || wsl?
    path = windows_unc_path(path)
  end
  path
end

.windows_unc_path(path) ⇒ String

Converts a given path to UNC format by adding a prefix and converting slashes.

Parameters:

  • path (String)

    Path to convert to UNC for Windows

Returns:

  • (String)


336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/vagrant/util/platform.rb', line 336

def windows_unc_path(path)
  path = path.gsub("/", "\\")

  # Convert to UNC path
  if path =~ /^[a-zA-Z]:\\?$/
    # If the path is just a drive letter, then return that as-is
    path + "\\"
  elsif path.start_with?("\\\\")
    # If the path already starts with `\\` assume UNC and return as-is
    path
  else
    "\\\\?\\" + path.gsub("/", "\\")
  end
end

.wsl?Boolean

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/vagrant/util/platform.rb', line 68

def wsl?
  if !defined?(@_wsl)
    @_wsl = false
    SilenceWarnings.silence! do
      # Find 'microsoft' in /proc/version indicative of WSL
      if File.file?('/proc/version')
        osversion = File.open('/proc/version', &:gets)
        if osversion.downcase.include?("microsoft")
          @_wsl = true
        end
      end
    end
  end
  @_wsl
end

.wsl_drvfs_mountsArray<String>

Get list of local mount paths that are DrvFs file systems

@todo(chrisroberts): Constantize types for check

Returns:

  • (Array<String>)


590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
# File 'lib/vagrant/util/platform.rb', line 590

def wsl_drvfs_mounts
  if !defined?(@_wsl_drvfs_mounts)
    @_wsl_drvfs_mounts = []
    if wsl?
      result = Util::Subprocess.execute("mount")
      result.stdout.each_line do |line|
        info = line.match(MOUNT_PATTERN)
        if info && (info[:type] == "drvfs" || info[:type] == "9p")
          @_wsl_drvfs_mounts << info[:mount]
        end
      end
    end
  end
  @_wsl_drvfs_mounts
end

.wsl_drvfs_path?(path) ⇒ Boolean

Check if given path is located on DrvFs file system

Parameters:

  • path (String, Pathname)

    Path to check

Returns:

  • (Boolean)


610
611
612
613
614
615
616
617
# File 'lib/vagrant/util/platform.rb', line 610

def wsl_drvfs_path?(path)
  if wsl?
    wsl_drvfs_mounts.each do |mount_path|
      return true if path.to_s.start_with?(mount_path)
    end
  end
  false
end

.wsl_init(env, logger = nil) ⇒ Object

If running within the Windows Subsystem for Linux, this will provide simple setup to allow sharing of the user's VAGRANT_HOME directory within the subsystem

Parameters:

  • env (Environment)
  • logger (Logger) (defaults to: nil)

    Optional logger to display information



625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
# File 'lib/vagrant/util/platform.rb', line 625

def wsl_init(env, logger=nil)
  if wsl?
    if ENV["VAGRANT_WSL_ENABLE_WINDOWS_ACCESS"]
      wsl_validate_matching_vagrant_versions!
      shared_user = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER"]
      if shared_user.to_s.empty?
        shared_user = wsl_windows_username
      end
      if logger
        logger.warn("Windows Subsystem for Linux detected. Allowing access to user: #{shared_user}")
        logger.warn("Vagrant will be allowed to control Vagrant managed machines within the user's home path.")
      end
      if ENV["VAGRANT_HOME"] || ENV["VAGRANT_WSL_DISABLE_VAGRANT_HOME"]
        logger.warn("VAGRANT_HOME environment variable already set. Not overriding!") if logger
      else
        home_path = wsl_windows_accessible_path.to_s
        ENV["VAGRANT_HOME"] = File.join(home_path, ".vagrant.d")
        if logger
          logger.info("Overriding VAGRANT_HOME environment variable to configured windows user. (#{ENV["VAGRANT_HOME"]})")
        end
        true
      end
    else
      if env.local_data_path.to_s.start_with?("/mnt/")
        raise Vagrant::Errors::WSLVagrantAccessError
      end
    end
  end
end

.wsl_path?(path) ⇒ Boolean

Determine if given path is within the WSL rootfs. Returns true if within the subsystem, or false if outside the subsystem.

Parameters:

  • path (String)

    Path to check

Returns:

  • (Boolean)

    path is within subsystem



379
380
381
# File 'lib/vagrant/util/platform.rb', line 379

def wsl_path?(path)
  wsl? && !path.to_s.downcase.start_with?("/mnt/")
end

.wsl_rootfsString

Compute the path to rootfs of currently active WSL.

Returns:

  • (String)

    A path to rootfs of a current WSL instance.



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/vagrant/util/platform.rb', line 386

def wsl_rootfs
  return @_wsl_rootfs if defined?(@_wsl_rootfs)

  if wsl?
    # Mark our filesystem with a temporary file having an unique name.
    marker = Tempfile.new(Time.now.to_i.to_s)
    logger = Log4r::Logger.new("vagrant::util::platform::wsl")

    # Check for lxrun installation first
    lxrun_path = [wsl_windows_appdata_local, "lxss"].join("\\")
    paths = [lxrun_path]

    logger.debug("checking registry for WSL installation path")
    paths += PowerShell.execute_cmd(
      '(Get-ChildItem HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss ' \
        '| ForEach-Object {Get-ItemProperty $_.PSPath}).BasePath').to_s.split("\r\n").map(&:strip)
    paths.delete_if{|path| path.to_s.empty?}

    paths.each do |path|
      # Lowercase the drive letter, skip the next symbol (which is a
      # colon from a Windows path) and convert path to UNIX style.
      check_path = "/mnt/#{path[0, 1].downcase}#{path[2..-1].tr('\\', '/')}/rootfs"
      begin
        process = Subprocess.execute("wslpath", "-u", "-a", path)
        check_path = "#{process.stdout.chomp}/rootfs" if process.exit_code == 0
      rescue Errors::CommandUnavailable => e
        # pass
      end

      logger.debug("checking `#{path}` for current WSL instance")
      begin
        # https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support
        # Current WSL instance doesn't have an access to its mount from
        # within itself despite all others are available. That's the
        # hacky way we're using to determine current instance.
        # For example we have three WSL instances:
        # A -> C:\User\USER\AppData\Local\Packages\A\LocalState\rootfs
        # B -> C:\User\USER\AppData\Local\Packages\B\LocalState\rootfs
        # C -> C:\User\USER\AppData\Local\Packages\C\LocalState\rootfs
        # If we're in "A" WSL at the moment, then its path will not be
        # accessible since it's mounted for exactly the instance we're
        # in. All others can be opened.
        Dir.open(check_path) do |fs|
          # A fallback for a case if our trick will stop working. For
          # that we've created a temporary file with an unique name in
          # a current WSL and now seeking it among all WSL.
          if File.exist?("#{fs.path}/#{marker.path}")
            @_wsl_rootfs = path
            break
          end
        end
      rescue Errno::EACCES
        @_wsl_rootfs = path
        # You can create and simultaneously run multiple WSL instances,
        # comment out the "break", run this script within each one and
        # it'll return only single value.
        break
      rescue Errno::ENOENT
        # Warn about data discrepancy between Winreg and file system
        # states. For the sake of justice, it's worth mentioning that
        # it is possible only when someone will manually break WSL by
        # removing a directory of its base path (kinda "stupid WSL
        # uninstallation by removing hidden and system directory").
        logger.warn("WSL instance at `#{path} is broken or no longer exists")
      end
      # All other exceptions have to be raised since they will mean
      # something unpredictably terrible.
    end

    marker.close!

    raise Vagrant::Errors::WSLRootFsNotFoundError if @_wsl_rootfs.nil?
  end

  # Attach the rootfs leaf to the path
  if @_wsl_rootfs != lxrun_path
    @_wsl_rootfs = "#{@_wsl_rootfs}\\rootfs"
  end

  logger.debug("detected `#{@_wsl_rootfs}` as current WSL instance")

  @_wsl_rootfs
end

.wsl_to_windows_path(path) ⇒ String

Convert a WSL path to the local Windows path. This is useful for conversion when calling out to Windows executables from the WSL

Parameters:

  • path (String, Pathname)

    Path to convert

Returns:

  • (String)


476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/vagrant/util/platform.rb', line 476

def wsl_to_windows_path(path)
  path = path.to_s
  if wsl? && wsl_windows_access? && !path.match(/^[a-zA-Z]:/)
    path = File.expand_path(path)
    begin
      process = Subprocess.execute("wslpath", "-w", "-a", path)
      return process.stdout.chomp if process.exit_code == 0
    rescue Errors::CommandUnavailable => e
      # pass
    end
    if wsl_path?(path)
      parts = path.split("/")
      parts.delete_if(&:empty?)
      root_path = wsl_rootfs
      # lxrun splits home separate so we need to account
      # for it's specialness here when we build the path
      if root_path.end_with?("lxss") && !(["root", "home"].include?(parts.first))
        root_path = "#{root_path}\\rootfs"
      end
      path = [root_path, *parts].join("\\")
    else
      path = path.sub("/mnt/", "")
      parts = path.split("/")
      parts.first << ":"
      path = parts.join("\\")
    end
  end
  path
end

.wsl_validate_matching_vagrant_versions!Object

Confirm Vagrant versions installed within the WSL and the Windows system are the same. Raise error if they do not match.



696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
# File 'lib/vagrant/util/platform.rb', line 696

def wsl_validate_matching_vagrant_versions!
  valid = false
  if Util::Which.which("vagrant.exe")
    result = Util::Subprocess.execute("vagrant.exe", "--version")
    if result.exit_code == 0
      windows_version = result.stdout.match(/Vagrant (?<version>[\w.-]+)/)
      if windows_version
        windows_version = windows_version[:version].strip
        valid = windows_version == Vagrant::VERSION
      end
    end
    if !valid
      raise Vagrant::Errors::WSLVagrantVersionMismatch,
        wsl_version: Vagrant::VERSION,
        windows_version: windows_version || "unknown"
    end
  end
end

.wsl_windows_access?Boolean

Allow Vagrant to access Vagrant managed machines outside the Windows Subsystem for Linux

Returns:

  • (Boolean)


542
543
544
545
546
547
# File 'lib/vagrant/util/platform.rb', line 542

def wsl_windows_access?
  if !defined?(@_wsl_windows_access)
    @_wsl_windows_access = wsl? && ENV["VAGRANT_WSL_ENABLE_WINDOWS_ACCESS"]
  end
  @_wsl_windows_access
end

.wsl_windows_access_bypass?(path) ⇒ Boolean

Checks given path to determine if Vagrant is allowed to bypass checks

Parameters:

  • path (String)

    Path to check

Returns:

  • (Boolean)

    Vagrant is allowed to bypass checks



578
579
580
581
# File 'lib/vagrant/util/platform.rb', line 578

def wsl_windows_access_bypass?(path)
  wsl? && wsl_windows_access? &&
    path.to_s.start_with?(wsl_windows_accessible_path.to_s)
end

.wsl_windows_accessible_pathPathname

The allowed windows system path Vagrant can manage from the Windows Subsystem for Linux

Returns:

  • (Pathname)


553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
# File 'lib/vagrant/util/platform.rb', line 553

def wsl_windows_accessible_path
  if !defined?(@_wsl_windows_accessible_path)
    access_path = ENV["VAGRANT_WSL_WINDOWS_ACCESS_USER_HOME_PATH"]
    if access_path.to_s.empty?
      begin
        process = Subprocess.execute("wslpath", "-u", "-a", wsl_windows_home)
        access_path = process.stdout.chomp if process.exit_code == 0
      rescue Errors::CommandUnavailable => e
        # pass
      end
    end
    if access_path.to_s.empty?
      access_path = wsl_windows_home.gsub("\\", "/").sub(":", "")
      access_path[0] = access_path[0].downcase
      access_path = "/mnt/#{access_path}"
    end
    @_wsl_windows_accessible_path = Pathname.new(access_path)
  end
  @_wsl_windows_accessible_path
end

.wsl_windows_appdata_localString, Nil

Fetch the Windows user local app data directory

Returns:

  • (String, Nil)


684
685
686
687
688
689
690
691
692
# File 'lib/vagrant/util/platform.rb', line 684

def wsl_windows_appdata_local
  if !@_wsl_windows_appdata_local
    result = Util::Subprocess.execute("cmd.exe", "/c", "echo %LOCALAPPDATA%")
    if result.exit_code == 0
      @_wsl_windows_appdata_local = result.stdout.gsub("\"", "").strip
    end
  end
  @_wsl_windows_appdata_local
end

.wsl_windows_homeString, Nil

Fetch the Windows user home directory

Returns:

  • (String, Nil)


671
672
673
674
675
676
677
678
679
# File 'lib/vagrant/util/platform.rb', line 671

def wsl_windows_home
  if !@_wsl_windows_home
    result = Util::Subprocess.execute("cmd.exe", "/c" "echo %USERPROFILE%")
    if result.exit_code == 0
      @_wsl_windows_home = result.stdout.gsub("\"", "").strip
    end
  end
  @_wsl_windows_home
end

.wsl_windows_usernameString, Nil

Fetch the Windows username currently in use

Returns:

  • (String, Nil)


658
659
660
661
662
663
664
665
666
# File 'lib/vagrant/util/platform.rb', line 658

def wsl_windows_username
  if !@_wsl_windows_username
    result = Util::Subprocess.execute("cmd.exe", "/c", "echo %USERNAME%")
    if result.exit_code == 0
      @_wsl_windows_username = result.stdout.strip
    end
  end
  @_wsl_windows_username
end