Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base: add Sys.detectwsl() #57069

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open

Conversation

inkydragon
Copy link
Member

@inkydragon inkydragon commented Jan 16, 2025

Replace #36425, fix #36354

How to detect WSL?

There are a number of ways that can be used to detect WSL environments,
but each can have false positives.

We finally chose to use the same method as Snapd to detect WSL.
Because Windows installs Ubuntu LTS as WSL by default.
So we assume that Snapd's detection method will work for most users.

Known limitations

  • this is a runtime test, and thus cannot meaningfully be used in @static if constructs.

  • Linux users can create their own

    • /proc/sys/fs/binfmt_misc/WSLInterop file
    • or /run/WSL/ folder

    to pretend to be a WSL environment.


  • I've tested this under: Ubuntu 22.04.5 LTS (default/Offical) and alpine-release-3.17.0 (win store)
  • Add compat, NEWS, tests
  • Take a look at different detect methods,
    figure out which one is more robust

mgautam98 and others added 4 commits January 16, 2025 21:26
@inkydragon inkydragon changed the title detectwsl base: add Sys.detectwsl() Jan 16, 2025
@inkydragon inkydragon added system:windows Affects only Windows system:wsl Windows Subsystem Linux (WSL) labels Jan 16, 2025
@inkydragon inkydragon marked this pull request as ready for review January 16, 2025 13:38
@inkydragon
Copy link
Member Author

inkydragon commented Jan 16, 2025

Seems all Linux platforms failed.

error during bootstrap:
LoadError("sysimg.jl", 5, LoadError("Base.jl", 127, LoadError("sysinfo.jl", 3, UndefVarError(:isfile, Base.Sys))))
ijl_undefined_var_error at [buildroot]/src/rtutils.c:152
detectwsl at ./sysinfo.jl:550

Maybe I need to use Base.Filesystem.isfile.
But why this line works?

if isfile(program_path) && isexecutable(program_path)

base/sysinfo.jl Outdated
@@ -532,7 +533,26 @@ including e.g. a WebAssembly JavaScript embedding in a web browser.
"""
isjsvm(os::Symbol) = (os === :Emscripten)

for f in (:isunix, :islinux, :isbsd, :isapple, :iswindows, :isfreebsd, :isopenbsd, :isnetbsd, :isdragonfly, :isjsvm)
"""
Sys.detectwsl([os])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps Sys.iswsl() for consistency with the other platform detection functions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually on purpose, as detectwsl detects at runtime, so names of the form is_platform are not used.
See discuss in #36354

base/sysinfo.jl Outdated Show resolved Hide resolved
base/sysinfo.jl Outdated Show resolved Hide resolved
@davidanthoff
Copy link
Contributor

There is already a WSL detection in base at

host = if ispath("/proc/sys/fs/binfmt_misc/WSLInterop") # WSL sigil
and it uses a slightly different approach. Would be good to figure out which one is more robust and then use that one consistently everywhere.

@ararslan
Copy link
Member

As a data point, Ubuntu's Snap daemon looks for /proc/sys/fs/binfmt_misc/WSLInterop to detect whether it's running on WSL, but it's apparently also possible to override the name to something other than WSLInterop. Looks like the approach implemented here is also fairly common.

Some references:

Co-authored-by: Alex Arslan <ararslan@comcast.net>
test/osutils.jl Outdated Show resolved Hide resolved
base/sysinfo.jl Outdated Show resolved Hide resolved
@davidanthoff
Copy link
Contributor

I read through the links that @ararslan posted, and to me the ispath("/proc/sys/fs/binfmt_misc/WSLInterop") methods seems more robust and simplest. My understanding is that one can only get false positives or false negatives there if a user really went out of their way to reconfigure things, essentially on purpose trying to prevent detection.

The superuser post also mentions on the other hand that the method implemented here in this PR might give a false positive maybe even on Azure, where MS might be running a custom kernel, and so greping for just "Microsoft" might get fooled.

I also think that if Ubuntu uses a given approach for snap, then it is probably a good idea to just follow that. Ubuntu and MS have worked really closely together on this whole WSL stuff, so just following their lead strikes me as a good idea.

@ararslan
Copy link
Member

I should note that my claim about Snap comes from the linked answer on SuperUser, which is from 2022; it's possible that Ubuntu has changed the implementation since then.

@inkydragon
Copy link
Member Author

inkydragon commented Jan 18, 2025

it's possible that Ubuntu has changed the implementation since then.

They added testing for the existence of “/run/WSL/” as a fallback.
We can use the same way to detect WSL.

// We detect WSL via the existence of /proc/sys/fs/binfmt_misc/WSLInterop
// Under some undocumented circumstances this file may be missing. We have /run/WSL as a backup.
//
// We detect WSL1 via the root filesystem type:
// - wslfs or lxfs mean WSL1
// - Anything else means WSL2
// After knowing we're in WSL, if any error occurs we assume WSL2 as it is the more flexible version
func getWSLVersion() int {
	if !fileExists("/proc/sys/fs/binfmt_misc/WSLInterop") && !fileExists("/run/WSL") {
		return 0
	}
	fstype, err := filesystemRootType()
	if err != nil {
		// TODO log error here once logger can be imported without circular imports
		return 2
	}

	if fstype == "wslfs" || fstype == "lxfs" {
		return 1
	}
	return 2
}

https://github.com/canonical/snapd/blob/03a578a5dff26467dcc80580fcd4720a486185a5/release/release.go#L151-L172


Some test under Ubuntu and alpine:

Ubuntu 22.04.5 LTS (default/Offical)

~$ lsb_release
No LSB modules are available.
~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.5 LTS
Release:        22.04
Codename:       jammy
~$ uname -a
Linux A309-Y9000P 5.15.137.3-microsoft-standard-WSL2+ #4 SMP Wed Jan 10 11:18:39 CST 2024 x86_64 x86_64 x86_64 GNU/Linux
~$ cat /proc/sys/fs/binfmt_misc/WSLInterop
enabled
interpreter /init
flags: PF
offset 0
magic 4d5a
~$ ls /run/WSL/
1_interop  2_interop  3217_interop  518_interop
~$ cat /proc/sys/kernel/osrelease
5.15.137.3-microsoft-standard-WSL2+
~$

alpine-release-3.17.0 (win store):

~$ cat /etc/alpine-release
3.17.0
~$ cat /proc/sys/fs/binfmt_misc/WSLInterop
enabled
interpreter /init
flags: PF
offset 0
magic 4d5a
~$ ls /run/WSL/
14_interop  1_interop
~$ cat /proc/sys/kernel/osrelease
5.15.137.3-microsoft-standard-WSL2+
~$

base/sysinfo.jl Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
system:windows Affects only Windows system:wsl Windows Subsystem Linux (WSL)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request] Sys.iswsl()
4 participants