mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 08:56:05 +08:00 
			
		
		
		
	Works around a problem where recent Windows updates do not always redirect the system wsl to the app store wsl version correctly. Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
		
			
				
	
	
		
			126 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//go:build windows
 | 
						|
 | 
						|
package wutil
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"syscall"
 | 
						|
 | 
						|
	"golang.org/x/text/encoding/unicode"
 | 
						|
	"golang.org/x/text/transform"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	once    sync.Once
 | 
						|
	wslPath string
 | 
						|
)
 | 
						|
 | 
						|
func FindWSL() string {
 | 
						|
	// At the time of this writing, a defect appeared in the OS preinstalled WSL executable
 | 
						|
	// where it no longer reliably locates the preferred Windows App Store variant.
 | 
						|
	//
 | 
						|
	// Manually discover (and cache) the wsl.exe location to bypass the problem
 | 
						|
	once.Do(func() {
 | 
						|
		var locs []string
 | 
						|
 | 
						|
		// Prefer Windows App Store version
 | 
						|
		if localapp := getLocalAppData(); localapp != "" {
 | 
						|
			locs = append(locs, filepath.Join(localapp, "Microsoft", "WindowsApps", "wsl.exe"))
 | 
						|
		}
 | 
						|
 | 
						|
		// Otherwise, the common location for the legacy system version
 | 
						|
		root := os.Getenv("SystemRoot")
 | 
						|
		if root == "" {
 | 
						|
			root = `C:\Windows`
 | 
						|
		}
 | 
						|
		locs = append(locs, filepath.Join(root, "System32", "wsl.exe"))
 | 
						|
 | 
						|
		for _, loc := range locs {
 | 
						|
			if _, err := os.Stat(loc); err == nil {
 | 
						|
				wslPath = loc
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Hope for the best
 | 
						|
		wslPath = "wsl"
 | 
						|
	})
 | 
						|
 | 
						|
	return wslPath
 | 
						|
}
 | 
						|
 | 
						|
func getLocalAppData() string {
 | 
						|
	localapp := os.Getenv("LOCALAPPDATA")
 | 
						|
	if localapp != "" {
 | 
						|
		return localapp
 | 
						|
	}
 | 
						|
 | 
						|
	if user := os.Getenv("USERPROFILE"); user != "" {
 | 
						|
		return filepath.Join(user, "AppData", "Local")
 | 
						|
	}
 | 
						|
 | 
						|
	return localapp
 | 
						|
}
 | 
						|
 | 
						|
func SilentExec(command string, args ...string) error {
 | 
						|
	cmd := exec.Command(command, args...)
 | 
						|
	cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
 | 
						|
	cmd.Stdout = nil
 | 
						|
	cmd.Stderr = nil
 | 
						|
	return cmd.Run()
 | 
						|
}
 | 
						|
 | 
						|
func SilentExecCmd(command string, args ...string) *exec.Cmd {
 | 
						|
	cmd := exec.Command(command, args...)
 | 
						|
	cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
 | 
						|
	return cmd
 | 
						|
}
 | 
						|
 | 
						|
func IsWSLInstalled() bool {
 | 
						|
	cmd := SilentExecCmd(FindWSL(), "--status")
 | 
						|
	out, err := cmd.StdoutPipe()
 | 
						|
	cmd.Stderr = nil
 | 
						|
	if err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	if err = cmd.Start(); err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	kernelNotFound := matchOutputLine(out, "kernel file is not found")
 | 
						|
 | 
						|
	if err := cmd.Wait(); err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	return !kernelNotFound
 | 
						|
}
 | 
						|
 | 
						|
func IsWSLStoreVersionInstalled() bool {
 | 
						|
	cmd := SilentExecCmd(FindWSL(), "--version")
 | 
						|
	cmd.Stdout = nil
 | 
						|
	cmd.Stderr = nil
 | 
						|
	if err := cmd.Run(); err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func matchOutputLine(output io.ReadCloser, match string) bool {
 | 
						|
	scanner := bufio.NewScanner(transform.NewReader(output, unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()))
 | 
						|
	for scanner.Scan() {
 | 
						|
		line := scanner.Text()
 | 
						|
		if strings.Contains(line, match) {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 |