aboutsummaryrefslogtreecommitdiff
path: root/cmd/podman-wslkerninst/main.go
blob: 0485db13c7582557cdc2e5c36c60ef19bd6dd543 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//go:build windows
// +build windows

package main

import (
	"fmt"
	"os"
	"path"
	"syscall"
	"time"
	"unsafe"

	"github.com/containers/podman/v4/pkg/machine/wsl"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/windows/svc/eventlog"
)

const (
	MB_ICONWARNING = 0x00000030
	MB_OK          = 0x00000000
	MB_DEFBUTTON1  = 0x00000000
)

const KernelWarning = "WSL Kernel installation did not complete successfully. " +
	"Podman machine will attempt to install this at a later time. " +
	"You can also manually complete the installation using the " +
	"\"wsl --update\" command."

func setupLogging(name string) (*eventlog.Log, error) {
	// Reuse the Built-in .NET Runtime Source so that we do not
	// have to provide a messaage table and modify the system
	// event configuration
	log, err := eventlog.Open(".NET Runtime")
	if err != nil {
		return nil, err
	}

	logrus.AddHook(NewEventHook(log, name))
	logrus.SetLevel(logrus.InfoLevel)

	return log, nil
}

func installWslKernel() error {
	logrus.Info("Installing WSL Kernel update")
	var (
		err error
	)
	backoff := 500 * time.Millisecond
	for i := 1; i < 6; i++ {
		err = wsl.SilentExec("wsl", "--update")
		if err == nil {
			break
		}

		// In case of unusual circumstances (e.g. race with installer actions)
		// retry a few times
		logrus.Warn("An error occurred attempting the WSL Kernel update, retrying...")
		time.Sleep(backoff)
		backoff *= 2
	}

	if err != nil {
		err = fmt.Errorf("could not install WSL Kernel: %w", err)
	}

	return err
}

// Creates an "warn" style pop-up window
func warn(title string, caption string) int {
	format := MB_ICONWARNING | MB_OK | MB_DEFBUTTON1

	user32 := syscall.NewLazyDLL("user32.dll")
	captionPtr, _ := syscall.UTF16PtrFromString(caption)
	titlePtr, _ := syscall.UTF16PtrFromString(title)
	ret, _, _ := user32.NewProc("MessageBoxW").Call(
		uintptr(0),
		uintptr(unsafe.Pointer(captionPtr)),
		uintptr(unsafe.Pointer(titlePtr)),
		uintptr(format))

	return int(ret)
}

func main() {
	args := os.Args
	setupLogging(path.Base(args[0]))
	if wsl.IsWSLInstalled() {
		// nothing to do
		logrus.Info("WSL Kernel already installed")
		return
	}

	result := installWslKernel()
	if result != nil {
		logrus.Error(result.Error())
		_ = warn("Podman Setup", KernelWarning)
	}

	logrus.Info("WSL Kernel update successful")
}