|
@@ -1,53 +1,55 @@
|
|
|
package operatingsystem // import "github.com/docker/docker/pkg/parsers/operatingsystem"
|
|
|
|
|
|
import (
|
|
|
- "fmt"
|
|
|
+ "errors"
|
|
|
|
|
|
"github.com/Microsoft/hcsshim/osversion"
|
|
|
+ "golang.org/x/sys/windows"
|
|
|
"golang.org/x/sys/windows/registry"
|
|
|
)
|
|
|
|
|
|
+// VER_NT_WORKSTATION, see https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa
|
|
|
+const verNTWorkstation = 0x00000001 // VER_NT_WORKSTATION
|
|
|
+
|
|
|
// GetOperatingSystem gets the name of the current operating system.
|
|
|
func GetOperatingSystem() (string, error) {
|
|
|
- os, err := withCurrentVersionRegistryKey(func(key registry.Key) (os string, err error) {
|
|
|
- if os, _, err = key.GetStringValue("ProductName"); err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
-
|
|
|
- releaseId, _, err := key.GetStringValue("ReleaseId")
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- os = fmt.Sprintf("%s Version %s", os, releaseId)
|
|
|
+ osversion := windows.RtlGetVersion() // Always succeeds.
|
|
|
+ rel := windowsOSRelease{
|
|
|
+ IsServer: osversion.ProductType != verNTWorkstation,
|
|
|
+ Build: osversion.BuildNumber,
|
|
|
+ }
|
|
|
|
|
|
- buildNumber, _, err := key.GetStringValue("CurrentBuildNumber")
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
+ // Make a best-effort attempt to retrieve the display version and
|
|
|
+ // Update Build Revision by querying undocumented registry values.
|
|
|
+ key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
|
|
+ if err == nil {
|
|
|
+ defer key.Close()
|
|
|
+ if ver, err := getFirstStringValue(key,
|
|
|
+ "DisplayVersion", /* Windows 20H2 and above */
|
|
|
+ "ReleaseId", /* Windows 2009 and below */
|
|
|
+ ); err == nil {
|
|
|
+ rel.DisplayVersion = ver
|
|
|
}
|
|
|
- ubr, _, err := key.GetIntegerValue("UBR")
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
+ if ubr, _, err := key.GetIntegerValue("UBR"); err == nil {
|
|
|
+ rel.UBR = ubr
|
|
|
}
|
|
|
- os = fmt.Sprintf("%s (OS Build %s.%d)", os, buildNumber, ubr)
|
|
|
-
|
|
|
- return
|
|
|
- })
|
|
|
-
|
|
|
- if os == "" {
|
|
|
- // Default return value
|
|
|
- os = "Unknown Operating System"
|
|
|
}
|
|
|
|
|
|
- return os, err
|
|
|
+ return rel.String(), nil
|
|
|
}
|
|
|
|
|
|
-func withCurrentVersionRegistryKey(f func(registry.Key) (string, error)) (string, error) {
|
|
|
- key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
+func getFirstStringValue(key registry.Key, names ...string) (string, error) {
|
|
|
+ for _, n := range names {
|
|
|
+ val, _, err := key.GetStringValue(n)
|
|
|
+ if err != nil {
|
|
|
+ if !errors.Is(err, registry.ErrNotExist) {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ return val, nil
|
|
|
}
|
|
|
- defer key.Close()
|
|
|
- return f(key)
|
|
|
+ return "", registry.ErrNotExist
|
|
|
}
|
|
|
|
|
|
// GetOperatingSystemVersion gets the version of the current operating system, as a string.
|