feat(system-info): improve Windows OS detection and categorization (#20117)
Costa Tsaousis committed
Apr 11, 2025 at 10:46 UTC
90a7ecb11a3854a1f4cfd584fcc155f66675ad2c
3 files changed
+75
-4
src/daemon/win_system-info.c
+74
-2
@@ -243,6 +243,78 @@ static void netdata_windows_os_kernel_version(char *out, DWORD length, DWORD bui
243
(void)snprintf(out, length, "Windows %u.%u.%u Build: %u", major, minor, build, build);
244
}
245
246
+static char *netdata_windows_get_edition(void)
247
+{
248
+ static char edition[256] = {0};
249
+
250
+ // Try to read EditionID first, which is more precise
251
+ if (netdata_registry_get_string(edition, sizeof(edition)-1, HKEY_LOCAL_MACHINE,
252
+ "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
253
+ "EditionID")) {
254
+ return edition;
255
+ }
256
+
257
+ // If EditionID fails, try ProductName
258
+ if (netdata_registry_get_string(edition, sizeof(edition)-1, HKEY_LOCAL_MACHINE,
259
+ "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
260
+ "ProductName")) {
261
+ return edition;
262
+ }
263
+
264
+ // Return unknown if both methods fail
265
+ return NETDATA_DEFAULT_SYSTEM_INFO_VALUE_UNKNOWN;
266
+}
267
+
268
+static char *netdata_windows_get_os_id_like(DWORD build)
269
+{
270
+ static char id_like[256];
271
+ char *edition = netdata_windows_get_edition();
272
+ const char *base_id = "";
273
+
274
+ if (IsWindowsServer()) {
275
+ // Windows Server versions based on build numbers
276
+ if (build >= 25000)
277
+ base_id = "Windows-Server-2025";
278
+ else if (build >= 20348)
279
+ base_id = "Windows-Server-2022";
280
+ else if (build >= 17763)
281
+ base_id = "Windows-Server-2019";
282
+ else if (build >= 14393)
283
+ base_id = "Windows-Server-2016";
284
+ else if (build >= 9600)
285
+ base_id = "Windows-Server-2012R2";
286
+ else if (build >= 9200)
287
+ base_id = "Windows-Server-2012";
288
+ else if (build >= 7601)
289
+ base_id = "Windows-Server-2008R2";
290
+ else
291
+ base_id = "Windows-Server";
292
+ } else {
293
+ // Windows client versions
294
+ if (build >= 22000)
295
+ base_id = "Windows-11";
296
+ else if (build >= 10240)
297
+ base_id = "Windows-10";
298
+ else if (build >= 9600)
299
+ base_id = "Windows-8.1";
300
+ else if (build >= 9200)
301
+ base_id = "Windows-8";
302
+ else if (build >= 7601)
303
+ base_id = "Windows-7";
304
+ else
305
+ base_id = "Windows";
306
+ }
307
+
308
+ // If we have a valid edition, append it to the ID_LIKE with a dash
309
+ if (strcmp(edition, NETDATA_DEFAULT_SYSTEM_INFO_VALUE_UNKNOWN) != 0) {
310
+ snprintf(id_like, sizeof(id_like), "%s-%s", base_id, edition);
311
+ } else {
312
+ strcpy(id_like, base_id);
313
+ }
314
+
315
+ return id_like;
316
+}
317
+
318
static void netdata_windows_host(struct rrdhost_system_info *systemInfo)
319
{
320
char osVersion[4096];
@@ -253,8 +325,8 @@ static void netdata_windows_host(struct rrdhost_system_info *systemInfo)
325
netdata_windows_discover_os_version(osVersion, 4095, build);
326
(void)rrdhost_system_info_set_by_name(systemInfo, "NETDATA_HOST_OS_ID", osVersion);
327
256
- (void)rrdhost_system_info_set_by_name(
257
- systemInfo, "NETDATA_HOST_OS_ID_LIKE", NETDATA_DEFAULT_SYSTEM_INFO_VALUE_UNKNOWN);
328
+ char *id_like = netdata_windows_get_os_id_like(build);
329
+ (void)rrdhost_system_info_set_by_name(systemInfo, "NETDATA_HOST_OS_ID_LIKE", id_like);
330
331
(void)rrdhost_system_info_set_by_name(systemInfo, "NETDATA_HOST_OS_VERSION", osVersion);
332
(void)rrdhost_system_info_set_by_name(systemInfo, "NETDATA_HOST_OS_VERSION_ID", osVersion);
src/daemon/win_system-info.h
+1
@@ -9,6 +9,7 @@
9
#define NETDATA_DEFAULT_SYSTEM_INFO_VALUE_UNKNOWN "unknown"
10
#define NETDATA_DEFAULT_SYSTEM_INFO_VALUE_NONE "none"
11
#define NETDATA_DEFAULT_SYSTEM_INFO_VALUE_FALSE "false"
12
+#define NETDATA_WIN_DETECTION_METHOD "windows-api"
13
14
#ifdef OS_WINDOWS
15
#include "windows.h"
src/libnetdata/os/os-windows-wrappers.h
-2
@@ -6,8 +6,6 @@
6
#include "../libnetdata.h"
7
8
#if defined(OS_WINDOWS)
9
-#define NETDATA_WIN_DETECTION_METHOD "Windows API/Registry"
10
-
9
long netdata_registry_get_dword_from_open_key(unsigned int *out, void *lKey, char *name);
10
bool netdata_registry_get_dword(unsigned int *out, void *hKey, char *subKey, char *name);
11