2
3
#include "status-file-dmi.h"
4
5
-#define safecpy(dst, src) do { \
6
- _Static_assert(sizeof(dst) != sizeof(char *), \
7
- "safecpy: dst must not be a pointer, but a buffer (e.g., char dst[SIZE])"); \
8
- strcatz(dst, 0, src, sizeof(dst)); \
9
-} while (0)
10
-
5
static void dmi_clean_field_placeholder(char *buf, size_t buf_size) {
6
if(!buf || !buf_size) return;
7
57
}
58
}
59
66
-static void dmi_normalize_vendor_field(char *buf, size_t buf_size) {
67
- if(!buf || !buf_size) return;
68
-
69
- struct {
70
- const char *found;
71
- const char *replace;
72
- } vendors[] = {
73
- {"QEMU", "KVM"},
74
-
75
- // Major vendors with multiple variations
76
- {"AMD Corporation", "AMD"},
77
- {"Advanced Micro Devices, Inc.", "AMD"},
78
-
79
- {"AMI Corp.", "AMI"},
80
- {"AMI Corporation", "AMI"},
81
- {"American Megatrends", "AMI"},
82
- {"American Megatrends Inc.", "AMI"},
83
- {"American Megatrends International", "AMI"},
84
- {"American Megatrends International, LLC.", "AMI"},
85
-
86
- {"AOPEN", "AOpen"},
87
- {"AOPEN Inc.", "AOpen"},
88
-
89
- {"Apache Software Foundation", "Apache"},
90
-
91
- {"Apple Inc.", "Apple"},
92
-
93
- {"ASRock Industrial", "ASRock"},
94
- {"ASRockRack", "ASRock"},
95
- {"AsrockRack", "ASRock"},
96
-
97
- {"ASUS", "ASUSTeK"},
98
- {"ASUSTeK COMPUTER INC.", "ASUSTeK"},
99
- {"ASUSTeK COMPUTER INC. (Licensed from AMI)", "ASUSTeK"},
100
- {"ASUSTeK Computer INC.", "ASUSTeK"},
101
- {"ASUSTeK Computer Inc.", "ASUSTeK"},
102
- {"ASUSTek Computer INC.", "ASUSTeK"},
103
-
104
- {"Apache Software Foundation", "Apache"},
105
-
106
- {"BESSTAR (HK) LIMITED", "Besstar"},
107
- {"BESSTAR TECH", "Besstar"},
108
- {"BESSTAR TECH LIMITED", "Besstar"},
109
- {"BESSTAR Tech", "Besstar"},
110
-
111
- {"CHUWI", "Chuwi"},
112
- {"CHUWI Innovation And Technology(ShenZhen)co.,Ltd", "Chuwi"},
113
-
114
- {"Cisco Systems Inc", "Cisco"},
115
- {"Cisco Systems, Inc.", "Cisco"},
116
-
117
- {"DELL", "Dell"},
118
- {"Dell Computer Corporation", "Dell"},
119
- {"Dell Inc.", "Dell"},
120
-
121
- {"FUJITSU", "Fujitsu"},
122
- {"FUJITSU CLIENT COMPUTING LIMITED", "Fujitsu"},
123
- {"FUJITSU SIEMENS", "Fujitsu"},
124
- {"FUJITSU SIEMENS // Phoenix Technologies Ltd.", "Fujitsu"},
125
- {"FUJITSU // American Megatrends Inc.", "Fujitsu"},
126
- {"FUJITSU // American Megatrends International, LLC.", "Fujitsu"},
127
- {"FUJITSU // Insyde Software Corp.", "Fujitsu"},
128
- {"FUJITSU // Phoenix Technologies Ltd.", "Fujitsu"},
129
-
130
- {"GIGABYTE", "Gigabyte"},
131
- {"Giga Computing", "Gigabyte"},
132
- {"Gigabyte Technology Co., Ltd.", "Gigabyte"},
133
- {"Gigabyte Tecohnology Co., Ltd.", "Gigabyte"},
134
-
135
- {"GOOGLE", "Google"},
136
- {"Google Inc", "Google"},
137
-
138
- {"HC Technology.,Ltd.", "HC Tech"},
139
-
140
- {"HP-Pavilion", "HP"},
141
- {"HPE", "HP"},
142
- {"Hewlett Packard Enterprise", "HP"},
143
- {"Hewlett-Packard", "HP"},
144
-
145
- {"HUAWEI", "Huawei"},
146
- {"Huawei Technologies Co., Ltd.", "Huawei"},
147
-
148
- {"IBM Corp.", "IBM"},
149
-
150
- {"INSYDE", "Insyde"},
151
- {"INSYDE Corp.", "Insyde"},
152
- {"Insyde Corp.", "Insyde"},
153
-
154
- {"INTEL", "Intel"},
155
- {"INTEL Corporation", "Intel"},
156
- {"Intel Corp.", "Intel"},
157
- {"Intel Corporation", "Intel"},
158
- {"Intel corporation", "Intel"},
159
- {"Intel(R) Client Systems", "Intel"},
160
- {"Intel(R) Corporation", "Intel"},
161
-
162
- {"LENOVO", "Lenovo"},
163
- {"LNVO", "Lenovo"},
164
-
165
- {"MICRO-STAR INTERNATIONAL CO., LTD", "MSI"},
166
- {"MICRO-STAR INTERNATIONAL CO.,LTD", "MSI"},
167
- {"MSI", "MSI"},
168
- {"Micro-Star International Co., Ltd", "MSI"},
169
- {"Micro-Star International Co., Ltd.", "MSI"},
170
-
171
- {"MICROSOFT", "Microsoft"},
172
- {"Microsoft Corporation", "Microsoft"},
173
-
174
- {"nVIDIA", "NVIDIA"},
175
-
176
- {"OPENSTACK", "OpenStack"},
177
- {"OpenStack Foundation", "OpenStack"},
178
-
179
- {"ORACLE CORPORATI", "Oracle"},
180
- {"Oracle Corporation", "Oracle"},
181
- {"innotek GmbH", "Oracle"},
182
-
183
- {"Phoenix Technologies LTD", "Phoenix"},
184
- {"Phoenix Technologies Ltd", "Phoenix"},
185
- {"Phoenix Technologies Ltd.", "Phoenix"},
186
- {"Phoenix Technologies, LTD", "Phoenix"},
187
-
188
- {"QNAP Systems, Inc.", "QNAP"},
189
-
190
- {"QUANTA", "Quanta"},
191
- {"Quanta Cloud Technology Inc.", "Quanta"},
192
- {"Quanta Computer Inc", "Quanta"},
193
- {"Quanta Computer Inc.", "Quanta"},
194
-
195
- {"RED HAT", "Red Hat"},
196
-
197
- {"SAMSUNG ELECTRONICS CO., LTD.", "Samsung"},
198
-
199
- {"SUN MICROSYSTEMS", "Sun"},
200
-
201
- {"SuperMicro", "Supermicro"},
202
- {"Supermicro Corporation", "Supermicro"},
203
-
204
- {"SYNOLOGY", "Synology"},
205
- {"Synology Inc.", "Synology"},
206
-
207
- {"TYAN", "Tyan"},
208
- {"TYAN Computer Corporation", "Tyan"},
209
- {"Tyan Computer Corporation", "Tyan"},
210
- {"$(TYAN_SYSTEM_MANUFACTURER)", "Tyan"},
211
-
212
- {"VMware", "VMware"},
213
- {"VMware, Inc.", "VMware"},
214
-
215
- {"XIAOMI", "Xiaomi"},
216
-
217
- {"ZOTAC", "Zotac"},
218
- {"Motherboard by ZOTAC", "Zotac"}
219
- };
220
-
221
- for (size_t i = 0; i < _countof(vendors); i++) {
222
- if (strcasecmp(buf, vendors[i].found) == 0) {
223
- strcatz(buf, 0, vendors[i].replace, buf_size);
224
- break;
225
- }
226
- }
227
-}
228
-
229
-static bool dmi_is_virtual_machine(const DAEMON_STATUS_FILE *ds) {
230
- if(!ds) return false;
231
-
232
- const char *vm_indicators[] = {
233
- "Virt", "KVM", "vServer", "Cloud", "Hyper", "Droplet", "Compute",
234
- "HVM domU", "Parallels", "(i440FX", "(q35", "OpenStack", "QEMU",
235
- "VMWare", "DigitalOcean", "Oracle", "Linode", "Amazon EC2"
236
- };
237
-
238
- const char *strs_to_check[] = {
239
- ds->hw.product.name,
240
- ds->hw.product.family,
241
- ds->hw.sys.vendor,
242
- ds->hw.board.name,
243
- };
244
-
245
- for (size_t i = 0; i < _countof(strs_to_check); i++) {
246
- if (!strs_to_check[i] || !strs_to_check[i][0])
247
- continue;
248
-
249
- for (size_t j = 0; j < _countof(vm_indicators); j++) {
250
- if (strcasestr(strs_to_check[i], vm_indicators[j]) != NULL)
251
- return true;
252
- }
253
- }
254
-
255
- return false;
256
-}
257
-
258
-static const char *dmi_chassis_type_to_string(int chassis_type) {
259
- // Original info from SMBIOS
260
- // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf
261
- // selected values aligned with inxi: https://github.com/smxi/inxi/blob/master/inxi
262
- switch(chassis_type) {
263
- case 1: return "other";
264
- case 2: return "unknown";
265
- case 3: return "desktop";
266
- case 4: return "desktop"; /* "low-profile-desktop" */
267
- case 5: return "pizza-box"; // was a 1 U desktop enclosure, but some old laptops also id this way
268
- case 6: return "desktop"; /* "mini-tower-desktop" */
269
- case 7: return "desktop"; /* "tower-desktop" */
270
- case 8: return "portable";
271
- case 9: return "laptop";
272
- case 10: return "laptop"; /* "notebook" */
273
- case 11: return "portable"; /* "hand-held" */
274
- case 12: return "docking-station";
275
- case 13: return "desktop"; /* "all-in-one" */
276
- case 14: return "notebook"; /* "sub-notebook" */
277
- case 15: return "desktop"; /* "space-saving-desktop" */
278
- case 16: return "laptop"; /* "lunch-box" */
279
- case 17: return "server"; /* "main-server-chassis" */
280
- case 18: return "expansion-chassis";
281
- case 19: return "sub-chassis";
282
- case 20: return "bus-expansion";
283
- case 21: return "peripheral";
284
- case 22: return "raid";
285
- case 23: return "server"; /* "rack-mount-server" */
286
- case 24: return "desktop"; /* "sealed-desktop" */
287
- case 25: return "server"; /* "multimount-chassis" */
288
- case 26: return "compact-pci";
289
- case 27: return "blade"; /* "advanced-tca" */
290
- case 28: return "blade";
291
- case 29: return "blade-enclosure";
292
- case 30: return "tablet";
293
- case 31: return "convertible";
294
- case 32: return "detachable";
295
- case 33: return "iot-gateway";
296
- case 34: return "embedded-pc";
297
- case 35: return "mini-pc";
298
- case 36: return "stick-pc";
299
- default: return NULL; // let it be numeric
300
- }
301
-}
302
-
303
-static void dmi_map_chassis_type(DAEMON_STATUS_FILE *ds, int chassis_type) {
304
- if(!ds) return;
305
-
306
- const char *str = NULL;
307
-
308
- if(dmi_is_virtual_machine(ds))
309
- str = "vm";
310
-
311
- if(!str)
312
- str = dmi_chassis_type_to_string(chassis_type);
313
-
314
- if(str)
315
- safecpy(ds->hw.chassis.type, str);
316
-}
317
-
60
static void dmi_clean_field(char *buf, size_t buf_size) {
61
if(!buf || !buf_size) return;
62
140
strcatz(dst, 0, buf, dst_size);
141
}
142
401
-void os_dmi_info(DAEMON_STATUS_FILE *ds) {
402
- linux_get_dmi_field("sys_vendor", NULL, ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
403
-
404
- linux_get_dmi_field("product_name", "/proc/device-tree/model", ds->hw.product.name, sizeof(ds->hw.product.name));
405
- linux_get_dmi_field("product_version", NULL, ds->hw.product.version, sizeof(ds->hw.product.version));
406
- linux_get_dmi_field("product_sku", NULL, ds->hw.product.sku, sizeof(ds->hw.product.sku));
407
- linux_get_dmi_field("product_family", NULL, ds->hw.product.family, sizeof(ds->hw.product.family));
408
-
409
- linux_get_dmi_field("chassis_vendor", NULL, ds->hw.chassis.vendor, sizeof(ds->hw.chassis.vendor));
410
- linux_get_dmi_field("chassis_version", NULL, ds->hw.chassis.version, sizeof(ds->hw.chassis.version));
411
-
412
- linux_get_dmi_field("board_vendor", NULL, ds->hw.board.vendor, sizeof(ds->hw.board.vendor));
413
- linux_get_dmi_field("board_name", NULL, ds->hw.board.name, sizeof(ds->hw.board.name));
414
- linux_get_dmi_field("board_version", NULL, ds->hw.board.version, sizeof(ds->hw.board.version));
415
-
416
- linux_get_dmi_field("bios_vendor", NULL, ds->hw.bios.vendor, sizeof(ds->hw.bios.vendor));
417
- linux_get_dmi_field("bios_version", NULL, ds->hw.bios.version, sizeof(ds->hw.bios.version));
418
- linux_get_dmi_field("bios_date", NULL, ds->hw.bios.date, sizeof(ds->hw.bios.date));
419
- linux_get_dmi_field("bios_release", NULL, ds->hw.bios.release, sizeof(ds->hw.bios.release));
420
-
421
- linux_get_dmi_field("chassis_type", NULL, ds->hw.chassis.type, sizeof(ds->hw.chassis.type));
143
+void os_dmi_info_get(DMI_INFO *dmi) {
144
+ if (!dmi) return;
145
+
146
+ linux_get_dmi_field("sys_vendor", NULL, dmi->sys.vendor, sizeof(dmi->sys.vendor));
147
+ linux_get_dmi_field("system_serial", NULL, dmi->sys.serial, sizeof(dmi->sys.serial));
148
+ linux_get_dmi_field("product_uuid", NULL, dmi->sys.uuid, sizeof(dmi->sys.uuid));
149
+ linux_get_dmi_field("chassis_asset_tag", NULL, dmi->sys.asset_tag, sizeof(dmi->sys.asset_tag));
150
+
151
+ linux_get_dmi_field("product_name", "/proc/device-tree/model", dmi->product.name, sizeof(dmi->product.name));
152
+ linux_get_dmi_field("product_version", NULL, dmi->product.version, sizeof(dmi->product.version));
153
+ linux_get_dmi_field("product_sku", NULL, dmi->product.sku, sizeof(dmi->product.sku));
154
+ linux_get_dmi_field("product_family", NULL, dmi->product.family, sizeof(dmi->product.family));
155
+
156
+ linux_get_dmi_field("chassis_vendor", NULL, dmi->chassis.vendor, sizeof(dmi->chassis.vendor));
157
+ linux_get_dmi_field("chassis_version", NULL, dmi->chassis.version, sizeof(dmi->chassis.version));
158
+ linux_get_dmi_field("chassis_serial", NULL, dmi->chassis.serial, sizeof(dmi->chassis.serial));
159
+ linux_get_dmi_field("chassis_asset_tag", NULL, dmi->chassis.asset_tag, sizeof(dmi->chassis.asset_tag));
160
+
161
+ linux_get_dmi_field("board_vendor", NULL, dmi->board.vendor, sizeof(dmi->board.vendor));
162
+ linux_get_dmi_field("board_name", NULL, dmi->board.name, sizeof(dmi->board.name));
163
+ linux_get_dmi_field("board_version", NULL, dmi->board.version, sizeof(dmi->board.version));
164
+ linux_get_dmi_field("board_serial", NULL, dmi->board.serial, sizeof(dmi->board.serial));
165
+ linux_get_dmi_field("board_asset_tag", NULL, dmi->board.asset_tag, sizeof(dmi->board.asset_tag));
166
+
167
+ linux_get_dmi_field("bios_vendor", NULL, dmi->bios.vendor, sizeof(dmi->bios.vendor));
168
+ linux_get_dmi_field("bios_version", NULL, dmi->bios.version, sizeof(dmi->bios.version));
169
+ linux_get_dmi_field("bios_date", NULL, dmi->bios.date, sizeof(dmi->bios.date));
170
+ linux_get_dmi_field("bios_release", NULL, dmi->bios.release, sizeof(dmi->bios.release));
171
+
172
+ linux_get_dmi_field("chassis_type", NULL, dmi->chassis.type, sizeof(dmi->chassis.type));
173
+
174
+ // Check if running in UEFI mode - just file existence, no external command
175
+ bool is_uefi = access("/sys/firmware/efi", F_OK) == 0;
176
+ if (is_uefi) {
177
+ safecpy(dmi->bios.mode, "UEFI");
178
+
179
+ // Check EFI variable for secure boot - direct file access, no external command
180
+ int fd = open("/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c", O_RDONLY);
181
+ if (fd != -1) {
182
+ // Skip the first 4 bytes which contain the EFI variable attributes
183
+ unsigned char value[5] = {0};
184
+ ssize_t bytes_read = read(fd, value, sizeof(value));
185
+ if (bytes_read == sizeof(value)) {
186
+ // The 5th byte (index 4) contains the secure boot status
187
+ dmi->bios.secure_boot = (value[4] == 1);
188
+ }
189
+ close(fd);
190
+ }
191
+
192
+ // Alternative check through securelevel - direct file access, no external command
193
+ if (!dmi->bios.secure_boot) {
194
+ fd = open("/sys/kernel/security/securelevel", O_RDONLY);
195
+ if (fd != -1) {
196
+ char level[10] = {0};
197
+ ssize_t bytes_read = read(fd, level, sizeof(level) - 1);
198
+ if (bytes_read > 0) {
199
+ level[bytes_read] = '\0'; // Ensure null termination
200
+ // If securelevel is > 0, usually means secure boot is enabled
201
+ int securelevel = atoi(level);
202
+ dmi->bios.secure_boot = (securelevel > 0);
203
+ }
204
+ close(fd);
205
+ }
206
+ }
207
+ } else {
208
+ safecpy(dmi->bios.mode, "Legacy");
209
+ }
210
}
211
#elif defined(OS_MACOS)
212
292
}
293
294
// Get hardware info from IODeviceTree
507
-static void get_devicetree_info(DAEMON_STATUS_FILE *ds) {
295
+static void get_devicetree_info(DMI_INFO *dmi) {
296
// Initialize all relevant fields to empty
509
- if (!ds)
297
+ if (!dmi)
298
return;
299
512
- ds->hw.product.name[0] = '\0';
513
- ds->hw.board.name[0] = '\0';
514
- ds->hw.sys.vendor[0] = '\0';
515
- ds->hw.product.family[0] = '\0';
300
+ dmi->product.name[0] = '\0';
301
+ dmi->board.name[0] = '\0';
302
+ dmi->sys.vendor[0] = '\0';
303
+ dmi->product.family[0] = '\0';
304
305
// Get the device tree
306
io_registry_entry_t device_tree = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/");
308
return;
309
310
// Get model information - only operate if device_tree is valid
523
- get_iokit_string_property(device_tree, CFSTR("model"), ds->hw.product.name, sizeof(ds->hw.product.name));
311
+ get_iokit_string_property(device_tree, CFSTR("model"), dmi->product.name, sizeof(dmi->product.name));
312
313
// Get board ID if available
526
- get_iokit_string_property(device_tree, CFSTR("board-id"), ds->hw.board.name, sizeof(ds->hw.board.name));
314
+ get_iokit_string_property(device_tree, CFSTR("board-id"), dmi->board.name, sizeof(dmi->board.name));
315
316
// Look for platform information
317
io_registry_entry_t platform = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/platform");
318
if (platform) {
319
// Platform information can sometimes have manufacturer info
532
- get_iokit_string_property(platform, CFSTR("manufacturer"), ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
320
+ get_iokit_string_property(platform, CFSTR("manufacturer"), dmi->sys.vendor, sizeof(dmi->sys.vendor));
321
322
// Check compatible property for additional info
323
char compatible[256] = {0};
328
char *family = strstr(compatible, ",");
329
if (family && family < compatible + sizeof(compatible) - 1) {
330
family++; // Skip the comma
543
- safecpy(ds->hw.product.family, family);
544
- dmi_clean_field(ds->hw.product.family, sizeof(ds->hw.product.family));
331
+ safecpy(dmi->product.family, family);
332
+ dmi_clean_field(dmi->product.family, sizeof(dmi->product.family));
333
}
334
}
335
340
}
341
342
// Get hardware info from IOPlatformExpertDevice
555
-static void get_platform_expert_info(DAEMON_STATUS_FILE *ds) {
556
- if (!ds)
343
+static void get_platform_expert_info(DMI_INFO *dmi) {
344
+ if (!dmi)
345
return;
346
347
io_registry_entry_t platform_expert = IORegistryEntryFromPath(
352
353
// System vendor - almost always "Apple Inc." for Macs
354
get_iokit_string_property(platform_expert, CFSTR("manufacturer"),
567
- ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
355
+ dmi->sys.vendor, sizeof(dmi->sys.vendor));
356
357
// Product name
358
get_iokit_string_property(platform_expert, CFSTR("model"),
571
- ds->hw.product.name, sizeof(ds->hw.product.name));
359
+ dmi->product.name, sizeof(dmi->product.name));
360
361
// Model number - can be used as product version
362
get_iokit_string_property(platform_expert, CFSTR("model-number"),
575
- ds->hw.product.version, sizeof(ds->hw.product.version));
363
+ dmi->product.version, sizeof(dmi->product.version));
364
365
// Board name sometimes available
366
get_iokit_string_property(platform_expert, CFSTR("board-id"),
579
- ds->hw.board.name, sizeof(ds->hw.board.name));
367
+ dmi->board.name, sizeof(dmi->board.name));
368
+
369
+ // System serial number - might be available as IOPlatformSerialNumber
370
+ get_iokit_string_property(platform_expert, CFSTR("IOPlatformSerialNumber"),
371
+ dmi->sys.serial, sizeof(dmi->sys.serial));
372
373
// Hardware UUID can be useful to include
374
char uuid_str[64] = {0};
375
get_iokit_string_property(platform_expert, CFSTR("IOPlatformUUID"), uuid_str, sizeof(uuid_str));
376
+
377
+ if (uuid_str[0])
378
+ safecpy(dmi->sys.uuid, uuid_str);
379
+
380
+ // For asset tag, try alternative properties since Apple doesn't provide a specific asset tag property
381
+ // First try chassis tag property if available
382
+ char asset_tag[64] = {0};
383
+ get_iokit_string_property(platform_expert, CFSTR("IOPlatformChassisTag"), asset_tag, sizeof(asset_tag));
384
+
385
+ // If not available, try using the serial number as an asset tag if not already set
386
+ if (!asset_tag[0]) {
387
+ // Model identifier can be a reasonable alternative for asset tag
388
+ get_iokit_string_property(platform_expert, CFSTR("model"), asset_tag, sizeof(asset_tag));
389
+ }
390
+
391
+ if (asset_tag[0] && (!dmi->sys.serial[0] || strcmp(asset_tag, dmi->sys.serial) != 0)) {
392
+ safecpy(dmi->sys.asset_tag, asset_tag);
393
+ }
394
395
// Get device type to determine chassis type
396
char device_type[64] = {0};
399
// Set chassis type based on device_type safely
400
if (device_type[0]) {
401
if (strcasestr(device_type, "laptop") || strcasestr(device_type, "book"))
592
- safecpy(ds->hw.chassis.type, "9");
402
+ safecpy(dmi->chassis.type, "9");
403
else if (strcasestr(device_type, "server"))
594
- safecpy(ds->hw.chassis.type, "17");
404
+ safecpy(dmi->chassis.type, "17");
405
else if (strcasestr(device_type, "imac"))
596
- safecpy(ds->hw.chassis.type, "13");
406
+ safecpy(dmi->chassis.type, "13");
407
else if (strcasestr(device_type, "mac"))
598
- safecpy(ds->hw.chassis.type, "3");
408
+ safecpy(dmi->chassis.type, "3");
409
}
410
411
// If chassis type not set, guess based on product name
602
- if (!ds->hw.chassis.type[0] && ds->hw.product.name[0]) {
603
- if (strcasestr(ds->hw.product.name, "book"))
604
- safecpy(ds->hw.chassis.type, "9");
605
- else if (strcasestr(ds->hw.product.name, "imac"))
606
- safecpy(ds->hw.chassis.type, "13");
607
- else if (strcasestr(ds->hw.product.name, "mac") && strcasestr(ds->hw.product.name, "pro"))
608
- safecpy(ds->hw.chassis.type, "3");
609
- else if (strcasestr(ds->hw.product.name, "mac") && strcasestr(ds->hw.product.name, "mini"))
610
- safecpy(ds->hw.chassis.type, "35");
412
+ if (!dmi->chassis.type[0] && dmi->product.name[0]) {
413
+ if (strcasestr(dmi->product.name, "book"))
414
+ safecpy(dmi->chassis.type, "9");
415
+ else if (strcasestr(dmi->product.name, "imac"))
416
+ safecpy(dmi->chassis.type, "13");
417
+ else if (strcasestr(dmi->product.name, "mac") && strcasestr(dmi->product.name, "pro"))
418
+ safecpy(dmi->chassis.type, "3");
419
+ else if (strcasestr(dmi->product.name, "mac") && strcasestr(dmi->product.name, "mini"))
420
+ safecpy(dmi->chassis.type, "35");
421
}
422
423
IOObjectRelease(platform_expert);
424
}
425
426
// Get SMC revision and system firmware info
617
-static void get_firmware_info(DAEMON_STATUS_FILE *ds) {
618
- if (!ds)
427
+static void get_firmware_info(DMI_INFO *dmi) {
428
+ if (!dmi)
429
return;
430
431
io_registry_entry_t smc = IOServiceGetMatchingService(
437
get_iokit_string_property(smc, CFSTR("smc-version"), smc_version, sizeof(smc_version));
438
439
if (smc_version[0]) {
630
- safecpy(ds->hw.bios.version, smc_version);
631
- dmi_clean_field(ds->hw.bios.version, sizeof(ds->hw.bios.version));
440
+ safecpy(dmi->bios.version, smc_version);
441
+ dmi_clean_field(dmi->bios.version, sizeof(dmi->bios.version));
442
}
443
444
IOObjectRelease(smc);
448
io_registry_entry_t rom = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/rom");
449
if (rom) {
450
// "version" contains firmware version
641
- get_iokit_string_property(rom, CFSTR("version"), ds->hw.bios.version, sizeof(ds->hw.bios.version));
451
+ get_iokit_string_property(rom, CFSTR("version"), dmi->bios.version, sizeof(dmi->bios.version));
452
453
// Apple is the vendor for all Mac firmware
644
- safecpy(ds->hw.bios.vendor, "Apple");
454
+ safecpy(dmi->bios.vendor, "Apple");
455
456
// "release-date" can sometimes be found
647
- get_iokit_string_property(rom, CFSTR("release-date"), ds->hw.bios.date, sizeof(ds->hw.bios.date));
457
+ get_iokit_string_property(rom, CFSTR("release-date"), dmi->bios.date, sizeof(dmi->bios.date));
458
459
IOObjectRelease(rom);
460
}
461
462
// If we still don't have BIOS version, check system version from sysctl
653
- if (!ds->hw.bios.version[0]) {
463
+ if (!dmi->bios.version[0]) {
464
char firmware_version[256] = {0};
465
size_t len = sizeof(firmware_version) - 1;
466
470
// Extract firmware info if present
471
char *firmware_info = strstr(firmware_version, "SMC:");
472
if (firmware_info && firmware_info < firmware_version + sizeof(firmware_version) - 1) {
663
- safecpy(ds->hw.bios.version, firmware_info);
664
- dmi_clean_field(ds->hw.bios.version, sizeof(ds->hw.bios.version));
473
+ safecpy(dmi->bios.version, firmware_info);
474
+ dmi_clean_field(dmi->bios.version, sizeof(dmi->bios.version));
475
}
476
}
477
}
478
}
479
480
// Get system hardware information using sysctl
671
-static void get_sysctl_info(DAEMON_STATUS_FILE *ds) {
672
- if (!ds)
481
+static void get_sysctl_info(DMI_INFO *dmi) {
482
+ if (!dmi)
483
return;
484
485
// Get model identifier using sysctl if not already set
676
- if (!ds->hw.product.name[0]) {
486
+ if (!dmi->product.name[0]) {
487
char model[256] = { 0 };
488
size_t len = sizeof(model) - 1;
489
490
if (sysctlbyname("hw.model", model, &len, NULL, 0) == 0) {
491
model[len] = '\0';
682
- safecpy(ds->hw.product.name, model);
683
- dmi_clean_field(ds->hw.product.name, sizeof(ds->hw.product.name));
492
+ safecpy(dmi->product.name, model);
493
+ dmi_clean_field(dmi->product.name, sizeof(dmi->product.name));
494
495
// If chassis type is still not set, guess from model
686
- if (!ds->hw.chassis.type[0]) {
496
+ if (!dmi->chassis.type[0]) {
497
if (strncasecmp(model, "MacBook", 7) == 0)
688
- safecpy(ds->hw.chassis.type, "9");
498
+ safecpy(dmi->chassis.type, "9");
499
else if (strncasecmp(model, "iMac", 4) == 0)
690
- safecpy(ds->hw.chassis.type, "13");
500
+ safecpy(dmi->chassis.type, "13");
501
else if (strncasecmp(model, "Mac", 3) == 0 && strcasestr(model, "Pro") != NULL)
692
- safecpy(ds->hw.chassis.type, "3");
502
+ safecpy(dmi->chassis.type, "3");
503
else if (strncasecmp(model, "Mac", 3) == 0 && strcasestr(model, "mini") != NULL)
694
- safecpy(ds->hw.chassis.type, "35");
504
+ safecpy(dmi->chassis.type, "35");
505
else
696
- safecpy(ds->hw.chassis.type, "3"); // Default to desktop
506
+ safecpy(dmi->chassis.type, "3"); // Default to desktop
507
}
508
}
509
}
510
511
// Get CPU information if board name not set
702
- if (!ds->hw.board.name[0]) {
512
+ if (!dmi->board.name[0]) {
513
char cpu_brand[256] = {0};
514
size_t len = sizeof(cpu_brand) - 1;
515
516
if (sysctlbyname("machdep.cpu.brand_string", cpu_brand, &len, NULL, 0) == 0) {
517
cpu_brand[len] = '\0'; // Ensure null termination
518
// Use CPU information as part of board info if not available
709
- safecpy(ds->hw.board.name, cpu_brand);
710
- dmi_clean_field(ds->hw.board.name, sizeof(ds->hw.board.name));
519
+ safecpy(dmi->board.name, cpu_brand);
520
+ dmi_clean_field(dmi->board.name, sizeof(dmi->board.name));
521
}
522
}
523
}
524
525
// Main function to get hardware info
716
-void os_dmi_info(DAEMON_STATUS_FILE *ds) {
717
- if (!ds) return;
526
+void os_dmi_info_get(DMI_INFO *dmi) {
527
+ if (!dmi) return;
528
529
// Always set Apple as default vendor
720
- safecpy(ds->hw.sys.vendor, "Apple");
530
+ safecpy(dmi->sys.vendor, "Apple");
531
532
// Get info from IOPlatformExpertDevice
723
- get_platform_expert_info(ds);
533
+ get_platform_expert_info(dmi);
534
535
// Get info from IODeviceTree
726
- get_devicetree_info(ds);
536
+ get_devicetree_info(dmi);
537
538
// Get firmware information
729
- get_firmware_info(ds);
539
+ get_firmware_info(dmi);
540
541
// Get additional info from sysctl
732
- get_sysctl_info(ds);
542
+ get_sysctl_info(dmi);
543
544
// Set board vendor to match system vendor if not set
735
- if (!ds->hw.board.vendor[0] && ds->hw.sys.vendor[0])
736
- safecpy(ds->hw.board.vendor, ds->hw.sys.vendor);
545
+ if (!dmi->board.vendor[0] && dmi->sys.vendor[0])
546
+ safecpy(dmi->board.vendor, dmi->sys.vendor);
547
548
// Set chassis vendor to match system vendor if not set
739
- if (!ds->hw.chassis.vendor[0] && ds->hw.sys.vendor[0])
740
- safecpy(ds->hw.chassis.vendor, ds->hw.sys.vendor);
549
+ if (!dmi->chassis.vendor[0] && dmi->sys.vendor[0])
550
+ safecpy(dmi->chassis.vendor, dmi->sys.vendor);
551
552
// Set bios vendor to match system vendor if not set
743
- if (!ds->hw.bios.vendor[0] && ds->hw.sys.vendor[0])
744
- safecpy(ds->hw.bios.vendor, ds->hw.sys.vendor);
553
+ if (!dmi->bios.vendor[0] && dmi->sys.vendor[0])
554
+ safecpy(dmi->bios.vendor, dmi->sys.vendor);
555
556
// Default product name if all methods failed
747
- if (!ds->hw.product.name[0])
748
- safecpy(ds->hw.product.name, "Mac");
557
+ if (!dmi->product.name[0])
558
+ safecpy(dmi->product.name, "Mac");
559
560
// Default chassis type if we couldn't determine it
751
- if (!ds->hw.chassis.type[0])
752
- safecpy(ds->hw.chassis.type, "3"); // Desktop
561
+ if (!dmi->chassis.type[0])
562
+ safecpy(dmi->chassis.type, "3"); // Desktop
563
+
564
+ // Check boot mode (UEFI vs Legacy) on macOS
565
+ io_registry_entry_t options = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
566
+ if (options) {
567
+ bool found_efi = false;
568
+ CFTypeRef property = IORegistryEntryCreateCFProperty(options, CFSTR("efi-boot-device"), kCFAllocatorDefault, 0);
569
+ if (property) {
570
+ found_efi = true;
571
+ CFRelease(property);
572
+ }
573
+
574
+ if (found_efi) {
575
+ safecpy(dmi->bios.mode, "UEFI");
576
+
577
+ // Check secure boot status
578
+ CFTypeRef secure_boot_prop = IORegistryEntryCreateCFProperty(options,
579
+ CFSTR("SecureBootLevel"),
580
+ kCFAllocatorDefault, 0);
581
+ if (secure_boot_prop) {
582
+ if (CFGetTypeID(secure_boot_prop) == CFNumberGetTypeID()) {
583
+ int level;
584
+ if (CFNumberGetValue((CFNumberRef)secure_boot_prop, kCFNumberIntType, &level)) {
585
+ // Any positive value indicates secure boot is enabled
586
+ dmi->bios.secure_boot = (level > 0);
587
+ }
588
+ }
589
+ CFRelease(secure_boot_prop);
590
+ }
591
+ } else {
592
+ safecpy(dmi->bios.mode, "Legacy");
593
+ }
594
+
595
+ IOObjectRelease(options);
596
+ } else {
597
+ safecpy(dmi->bios.mode, "Unknown");
598
+ }
599
+
600
+ // Check for Apple T2 security chip (similar to TPM but without using external commands)
601
+ // This uses only IOKit APIs which are safe and built-in
602
+ io_registry_entry_t chip = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/AppleACPIPlatformExpert/SMC/AppleT2:");
603
+ if (chip) {
604
+ // If T2 chip is present, secure boot is likely enabled
605
+ dmi->bios.secure_boot = true;
606
+ IOObjectRelease(chip);
607
+ }
608
}
609
610
#elif defined(OS_FREEBSD)
633
}
634
}
635
781
-void os_dmi_info(DAEMON_STATUS_FILE *ds) {
636
+void os_dmi_info_get(DMI_INFO *dmi) {
637
+ if (!dmi) return;
638
+
639
// System information from SMBIOS
783
- freebsd_get_sysctl_str("hw.vendor", ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
784
- freebsd_get_sysctl_str("hw.product", ds->hw.product.name, sizeof(ds->hw.product.name));
785
- freebsd_get_sysctl_str("hw.version", ds->hw.product.version, sizeof(ds->hw.product.version));
640
+ freebsd_get_sysctl_str("hw.vendor", dmi->sys.vendor, sizeof(dmi->sys.vendor));
641
+ freebsd_get_sysctl_str("hw.product", dmi->product.name, sizeof(dmi->product.name));
642
+ freebsd_get_sysctl_str("hw.version", dmi->product.version, sizeof(dmi->product.version));
643
+ freebsd_get_sysctl_str("hw.serial", dmi->sys.serial, sizeof(dmi->sys.serial));
644
645
// Try using kenv for additional information
788
- freebsd_get_kenv_str("smbios.system.maker", ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
789
- freebsd_get_kenv_str("smbios.system.product", ds->hw.product.name, sizeof(ds->hw.product.name));
790
- freebsd_get_kenv_str("smbios.system.version", ds->hw.product.version, sizeof(ds->hw.product.version));
791
- freebsd_get_kenv_str("smbios.system.sku", ds->hw.product.sku, sizeof(ds->hw.product.sku));
792
- freebsd_get_kenv_str("smbios.system.family", ds->hw.product.family, sizeof(ds->hw.product.family));
646
+ freebsd_get_kenv_str("smbios.system.maker", dmi->sys.vendor, sizeof(dmi->sys.vendor));
647
+ freebsd_get_kenv_str("smbios.system.product", dmi->product.name, sizeof(dmi->product.name));
648
+ freebsd_get_kenv_str("smbios.system.version", dmi->product.version, sizeof(dmi->product.version));
649
+ freebsd_get_kenv_str("smbios.system.sku", dmi->product.sku, sizeof(dmi->product.sku));
650
+ freebsd_get_kenv_str("smbios.system.family", dmi->product.family, sizeof(dmi->product.family));
651
+ freebsd_get_kenv_str("smbios.system.serial", dmi->sys.serial, sizeof(dmi->sys.serial));
652
653
// Board information
795
- freebsd_get_kenv_str("smbios.planar.maker", ds->hw.board.vendor, sizeof(ds->hw.board.vendor));
796
- freebsd_get_kenv_str("smbios.planar.product", ds->hw.board.name, sizeof(ds->hw.board.name));
797
- freebsd_get_kenv_str("smbios.planar.version", ds->hw.board.version, sizeof(ds->hw.board.version));
654
+ freebsd_get_kenv_str("smbios.planar.maker", dmi->board.vendor, sizeof(dmi->board.vendor));
655
+ freebsd_get_kenv_str("smbios.planar.product", dmi->board.name, sizeof(dmi->board.name));
656
+ freebsd_get_kenv_str("smbios.planar.version", dmi->board.version, sizeof(dmi->board.version));
657
+ freebsd_get_kenv_str("smbios.planar.serial", dmi->board.serial, sizeof(dmi->board.serial));
658
659
// BIOS information
800
- freebsd_get_kenv_str("smbios.bios.vendor", ds->hw.bios.vendor, sizeof(ds->hw.bios.vendor));
801
- freebsd_get_kenv_str("smbios.bios.version", ds->hw.bios.version, sizeof(ds->hw.bios.version));
802
- freebsd_get_kenv_str("smbios.bios.reldate", ds->hw.bios.date, sizeof(ds->hw.bios.date));
803
- freebsd_get_kenv_str("smbios.bios.release", ds->hw.bios.release, sizeof(ds->hw.bios.release));
660
+ freebsd_get_kenv_str("smbios.bios.vendor", dmi->bios.vendor, sizeof(dmi->bios.vendor));
661
+ freebsd_get_kenv_str("smbios.bios.version", dmi->bios.version, sizeof(dmi->bios.version));
662
+ freebsd_get_kenv_str("smbios.bios.reldate", dmi->bios.date, sizeof(dmi->bios.date));
663
+ freebsd_get_kenv_str("smbios.bios.release", dmi->bios.release, sizeof(dmi->bios.release));
664
665
// Chassis information
806
- freebsd_get_kenv_str("smbios.chassis.maker", ds->hw.chassis.vendor, sizeof(ds->hw.chassis.vendor));
807
- freebsd_get_kenv_str("smbios.chassis.version", ds->hw.chassis.version, sizeof(ds->hw.chassis.version));
666
+ freebsd_get_kenv_str("smbios.chassis.maker", dmi->chassis.vendor, sizeof(dmi->chassis.vendor));
667
+ freebsd_get_kenv_str("smbios.chassis.version", dmi->chassis.version, sizeof(dmi->chassis.version));
668
+ freebsd_get_kenv_str("smbios.chassis.serial", dmi->chassis.serial, sizeof(dmi->chassis.serial));
669
670
// Chassis type
810
- char chassis_type[16] = "";
811
- freebsd_get_kenv_str("smbios.chassis.type", chassis_type, sizeof(chassis_type));
812
- if (chassis_type[0]) {
813
- int type = atoi(chassis_type);
814
- if (type > 0)
815
- snprintf(ds->hw.chassis.type, sizeof(ds->hw.chassis.type), "%d", type);
816
- }
671
+ freebsd_get_kenv_str("smbios.chassis.type", dmi->chassis.type, sizeof(dmi->chassis.type));
672
673
// If we couldn't get system information from SMBIOS, try to use model
819
- if (!ds->hw.product.name[0])
820
- freebsd_get_sysctl_str("hw.model", ds->hw.product.name, sizeof(ds->hw.product.name));
674
+ if (!dmi->product.name[0])
675
+ freebsd_get_sysctl_str("hw.model", dmi->product.name, sizeof(dmi->product.name));
676
+
677
+ // Try to get asset tags
678
+ freebsd_get_kenv_str("smbios.system.asset_tag", dmi->sys.asset_tag, sizeof(dmi->sys.asset_tag));
679
+ freebsd_get_kenv_str("smbios.chassis.asset_tag", dmi->chassis.asset_tag, sizeof(dmi->chassis.asset_tag));
680
+ freebsd_get_kenv_str("smbios.planar.asset_tag", dmi->board.asset_tag, sizeof(dmi->board.asset_tag));
681
+
682
+ // Get UUID
683
+ freebsd_get_kenv_str("smbios.system.uuid", dmi->sys.uuid, sizeof(dmi->sys.uuid));
684
+
685
+ // Check for UEFI boot mode using sysctl (no external commands)
686
+ char bootmethod[64] = {0};
687
+ size_t bootmethod_size = sizeof(bootmethod) - 1;
688
+ if (sysctlbyname("kern.bootmethod", bootmethod, &bootmethod_size, NULL, 0) == 0) {
689
+ if (strncmp(bootmethod, "UEFI", 4) == 0) {
690
+ safecpy(dmi->bios.mode, "UEFI");
691
+
692
+ // Check secure boot status - FreeBSD stores this in sysctl (no external commands)
693
+ int secure_boot_enabled = 0;
694
+ size_t secboot_size = sizeof(secure_boot_enabled);
695
+ if (sysctlbyname("kern.secureboot.enable", &secure_boot_enabled, &secboot_size, NULL, 0) == 0) {
696
+ dmi->bios.secure_boot = (secure_boot_enabled != 0);
697
+ }
698
+ } else {
699
+ safecpy(dmi->bios.mode, "Legacy");
700
+ }
701
+ } else {
702
+ // Fallback: check for EFI presence (older FreeBSD versions) - no external commands
703
+ int efi_present = 0;
704
+ size_t efi_size = sizeof(efi_present);
705
+ if (sysctlbyname("kern.efi.runtime", &efi_present, &efi_size, NULL, 0) == 0) {
706
+ if (efi_present) {
707
+ safecpy(dmi->bios.mode, "UEFI");
708
+ } else {
709
+ safecpy(dmi->bios.mode, "Legacy");
710
+ }
711
+ }
712
+ }
713
}
714
715
#elif defined(OS_WINDOWS)
852
853
// Process BIOS Information (Type 0)
854
static void process_smbios_bios_info(const smbios_header_t *header,
963
- DAEMON_STATUS_FILE *ds,
855
+ DMI_INFO *dmi,
856
const char *string_table,
857
const BYTE *smbios_data,
858
DWORD smbios_size) {
967
- if (header->length < 18) // Minimum size for BIOS info
859
+ if (header->length < 18 || !dmi) // Minimum size for BIOS info
860
return;
861
862
const BYTE *data = (const BYTE *)header;
865
// BIOS Vendor (string index at offset 4)
866
if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
867
data[4], temp_str, sizeof(temp_str))) {
976
- safecpy(ds->hw.bios.vendor, temp_str);
868
+ safecpy(dmi->bios.vendor, temp_str);
869
}
870
871
// BIOS Version (string index at offset 5)
872
if (data[5] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
873
data[5], temp_str, sizeof(temp_str))) {
982
- safecpy(ds->hw.bios.version, temp_str);
874
+ safecpy(dmi->bios.version, temp_str);
875
}
876
877
// BIOS Release Date (string index at offset 8)
878
if (data[8] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
879
data[8], temp_str, sizeof(temp_str))) {
988
- safecpy(ds->hw.bios.date, temp_str);
880
+ safecpy(dmi->bios.date, temp_str);
881
}
882
}
883
884
// Process System Information (Type 1)
885
static void process_smbios_system_info(const smbios_header_t *header,
994
- DAEMON_STATUS_FILE *ds,
886
+ DMI_INFO *dmi,
887
const char *string_table,
888
const BYTE *smbios_data,
889
DWORD smbios_size) {
998
- if (header->length < 8) // Minimum size for System info
890
+ if (header->length < 8 || !dmi) // Minimum size for System info
891
return;
892
893
const BYTE *data = (const BYTE *)header;
896
// Manufacturer (string index at offset 4)
897
if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
898
data[4], temp_str, sizeof(temp_str))) {
1007
- safecpy(ds->hw.sys.vendor, temp_str);
899
+ safecpy(dmi->sys.vendor, temp_str);
900
}
901
902
// Product Name (string index at offset 5)
903
if (data[5] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
904
data[5], temp_str, sizeof(temp_str))) {
1013
- safecpy(ds->hw.product.name, temp_str);
905
+ safecpy(dmi->product.name, temp_str);
906
}
907
908
// Version (string index at offset 6)
909
if (data[6] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
910
data[6], temp_str, sizeof(temp_str))) {
1019
- safecpy(ds->hw.product.version, temp_str);
911
+ safecpy(dmi->product.version, temp_str);
912
+ }
913
+
914
+ // Serial Number (string index at offset 7)
915
+ if (data[7] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
916
+ data[7], temp_str, sizeof(temp_str))) {
917
+ safecpy(dmi->sys.serial, temp_str);
918
}
919
920
// If structure is long enough for family (SMBIOS 2.1+)
921
if (header->length >= 25 && data[21] > 0 &&
922
get_smbios_string(smbios_data, smbios_size, string_table,
923
data[21], temp_str, sizeof(temp_str))) {
1026
- safecpy(ds->hw.product.family, temp_str);
924
+ safecpy(dmi->product.family, temp_str);
925
+ }
926
+
927
+ // Extract system UUID (16 bytes starting at offset 8)
928
+ if (header->length >= 24) {
929
+ // Verify we have enough data to access all bytes safely
930
+ if ((uintptr_t)data + 23 < (uintptr_t)smbios_data + smbios_size) {
931
+ // UUID is stored as 16 bytes, we'll format it as a standard UUID string
932
+ char uuid_str[40] = {0}; // 36 chars for UUID + null terminator
933
+
934
+ // Note: SMBIOS UUID needs byte swapping for first three fields
935
+ int ret = snprintf(uuid_str, sizeof(uuid_str),
936
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
937
+ data[11], data[10], data[9], data[8], // field 1 (byte swapped)
938
+ data[13], data[12], // field 2 (byte swapped)
939
+ data[15], data[14], // field 3 (byte swapped)
940
+ data[16], data[17], // field 4 (not swapped)
941
+ data[18], data[19], data[20], data[21], data[22], data[23]); // field 5 (not swapped)
942
+
943
+ // Verify the formatting worked and buffer wasn't truncated
944
+ if (ret > 0 && ret < (int)sizeof(uuid_str)) {
945
+ // Only set if not all zeros (some systems report all zeros)
946
+ if (uuid_str[0] != '0' || uuid_str[1] != '0' || uuid_str[2] != '0' || uuid_str[3] != '0') {
947
+ safecpy(dmi->sys.uuid, uuid_str);
948
+ }
949
+ }
950
+ }
951
+ }
952
+
953
+ // Asset Tag is sometimes available in newer SMBIOS versions
954
+ if (header->length >= 27 && data[26] > 0 &&
955
+ get_smbios_string(smbios_data, smbios_size, string_table,
956
+ data[26], temp_str, sizeof(temp_str))) {
957
+ safecpy(dmi->sys.asset_tag, temp_str);
958
}
959
}
960
961
// Process Baseboard Information (Type 2)
962
static void process_smbios_baseboard_info(const smbios_header_t *header,
1032
- DAEMON_STATUS_FILE *ds,
963
+ DMI_INFO *dmi,
964
const char *string_table,
965
const BYTE *smbios_data,
966
DWORD smbios_size) {
1036
- if (header->length < 8) // Minimum size for Baseboard info
967
+ if (header->length < 8 || !dmi) // Minimum size for Baseboard info
968
return;
969
970
const BYTE *data = (const BYTE *)header;
973
// Manufacturer (string index at offset 4)
974
if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
975
data[4], temp_str, sizeof(temp_str))) {
1045
- safecpy(ds->hw.board.vendor, temp_str);
976
+ safecpy(dmi->board.vendor, temp_str);
977
}
978
979
// Product (string index at offset 5)
980
if (data[5] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
981
data[5], temp_str, sizeof(temp_str))) {
1051
- safecpy(ds->hw.board.name, temp_str);
982
+ safecpy(dmi->board.name, temp_str);
983
}
984
985
// Version (string index at offset 6)
986
if (data[6] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
987
data[6], temp_str, sizeof(temp_str))) {
1057
- safecpy(ds->hw.board.version, temp_str);
988
+ safecpy(dmi->board.version, temp_str);
989
+ }
990
+
991
+ // Serial Number (string index at offset 7)
992
+ if (data[7] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
993
+ data[7], temp_str, sizeof(temp_str))) {
994
+ safecpy(dmi->board.serial, temp_str);
995
+ }
996
+
997
+ // Asset Tag (string index at offset 8)
998
+ if (header->length >= 9 && data[8] > 0 &&
999
+ get_smbios_string(smbios_data, smbios_size, string_table,
1000
+ data[8], temp_str, sizeof(temp_str))) {
1001
+ safecpy(dmi->board.asset_tag, temp_str);
1002
}
1003
}
1004
1005
// Process Chassis Information (Type 3)
1006
static void process_smbios_chassis_info(const smbios_header_t *header,
1063
- DAEMON_STATUS_FILE *ds,
1007
+ DMI_INFO *dmi,
1008
const char *string_table,
1009
const BYTE *smbios_data,
1010
DWORD smbios_size) {
1067
- if (header->length < 9) // Minimum size for Chassis info
1011
+ if (header->length < 9 || !dmi) // Minimum size for Chassis info
1012
return;
1013
1014
const BYTE *data = (const BYTE *)header;
1017
// Manufacturer (string index at offset 4)
1018
if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
1019
data[4], temp_str, sizeof(temp_str))) {
1076
- safecpy(ds->hw.chassis.vendor, temp_str);
1020
+ safecpy(dmi->chassis.vendor, temp_str);
1021
}
1022
1023
// Type (numerical value at offset 5)
1024
BYTE chassis_type = data[5] & 0x7F; // Mask out MSB
1081
- if (chassis_type > 0 && chassis_type < 36) // Valid range check
1082
- snprintf(ds->hw.chassis.type, sizeof(ds->hw.chassis.type), "%d", chassis_type);
1025
+ snprintf(dmi->chassis.type, sizeof(dmi->chassis.type), "%d", chassis_type);
1026
1027
// Version (string index at offset 6)
1028
if (data[6] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
1029
data[6], temp_str, sizeof(temp_str))) {
1087
- safecpy(ds->hw.chassis.version, temp_str);
1030
+ safecpy(dmi->chassis.version, temp_str);
1031
+ }
1032
+
1033
+ // Serial Number (string index at offset 7)
1034
+ if (data[7] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
1035
+ data[7], temp_str, sizeof(temp_str))) {
1036
+ safecpy(dmi->chassis.serial, temp_str);
1037
+ }
1038
+
1039
+ // Asset Tag (string index at offset 8)
1040
+ if (header->length >= 9 && data[8] > 0 &&
1041
+ get_smbios_string(smbios_data, smbios_size, string_table,
1042
+ data[8], temp_str, sizeof(temp_str))) {
1043
+ safecpy(dmi->chassis.asset_tag, temp_str);
1044
}
1045
}
1046
1047
// Process a complete SMBIOS structure
1048
static void process_smbios_structure(const smbios_header_t *header,
1093
- DAEMON_STATUS_FILE *ds,
1049
+ DMI_INFO *dmi,
1050
const char *string_table,
1051
const BYTE *smbios_data,
1052
DWORD smbios_size) {
1053
+ if (!dmi) return;
1054
+
1055
switch (header->type) {
1056
case 0: // BIOS Information
1099
- process_smbios_bios_info(header, ds, string_table, smbios_data, smbios_size);
1057
+ process_smbios_bios_info(header, dmi, string_table, smbios_data, smbios_size);
1058
break;
1059
1060
case 1: // System Information
1103
- process_smbios_system_info(header, ds, string_table, smbios_data, smbios_size);
1061
+ process_smbios_system_info(header, dmi, string_table, smbios_data, smbios_size);
1062
break;
1063
1064
case 2: // Baseboard Information
1107
- process_smbios_baseboard_info(header, ds, string_table, smbios_data, smbios_size);
1065
+ process_smbios_baseboard_info(header, dmi, string_table, smbios_data, smbios_size);
1066
break;
1067
1068
case 3: // Chassis Information
1111
- process_smbios_chassis_info(header, ds, string_table, smbios_data, smbios_size);
1069
+ process_smbios_chassis_info(header, dmi, string_table, smbios_data, smbios_size);
1070
break;
1071
}
1072
}
1073
1074
// Parse all SMBIOS structures with robust error handling
1117
-static void parse_smbios_structures(const smbios_data_t smbios, DAEMON_STATUS_FILE *ds) {
1118
- if (!smbios.valid || !smbios.data || smbios.size < 8)
1075
+static void parse_smbios_structures(const smbios_data_t smbios, DMI_INFO *dmi) {
1076
+ if (!smbios.valid || !smbios.data || smbios.size < 8 || !dmi)
1077
return;
1078
1079
// The SMBIOS header is at offset 8
1132
// Process the structure based on type
1133
const char *string_table = (const char *)(current + header->length);
1134
if (string_table < (const char *)end) {
1177
- process_smbios_structure(header, ds, string_table, smbios.data, smbios.size);
1135
+ process_smbios_structure(header, dmi, string_table, smbios.data, smbios.size);
1136
}
1137
1138
// Find string table end (double null terminator)
1166
break;
1167
}
1168
}
1211
-static void windows_get_smbios_info(DAEMON_STATUS_FILE *ds) {
1169
+static void windows_get_smbios_info(DMI_INFO *dmi) {
1170
+ if (!dmi) return;
1171
+
1172
// Get SMBIOS data using our improved container structure
1173
smbios_data_t smbios = get_smbios_data();
1174
if (!smbios.valid)
1175
return;
1176
1177
// Process the SMBIOS data with our improved parser
1218
- parse_smbios_structures(smbios, ds);
1178
+ parse_smbios_structures(smbios, dmi);
1179
1180
// Clean up
1181
freez(smbios.data);
1182
}
1183
1184
// Fallback method using registry
1225
-static void windows_get_registry_info(DAEMON_STATUS_FILE *ds) {
1185
+static void windows_get_registry_info(DMI_INFO *dmi) {
1186
+ if (!dmi) return;
1187
+
1188
// System manufacturer and model from registry
1189
windows_read_registry_string(
1190
HKEY_LOCAL_MACHINE,
1191
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1192
"SystemManufacturer",
1231
- ds->hw.sys.vendor,
1232
- sizeof(ds->hw.sys.vendor)
1193
+ dmi->sys.vendor,
1194
+ sizeof(dmi->sys.vendor)
1195
);
1196
1197
windows_read_registry_string(
1198
HKEY_LOCAL_MACHINE,
1199
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1200
"SystemProductName",
1239
- ds->hw.product.name,
1240
- sizeof(ds->hw.product.name)
1201
+ dmi->product.name,
1202
+ sizeof(dmi->product.name)
1203
+ );
1204
+
1205
+ // System Serial Number
1206
+ windows_read_registry_string(
1207
+ HKEY_LOCAL_MACHINE,
1208
+ "HARDWARE\\DESCRIPTION\\System\\BIOS",
1209
+ "SystemSerialNumber",
1210
+ dmi->sys.serial,
1211
+ sizeof(dmi->sys.serial)
1212
);
1213
1214
// BIOS information
1216
HKEY_LOCAL_MACHINE,
1217
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1218
"BIOSVendor",
1248
- ds->hw.bios.vendor,
1249
- sizeof(ds->hw.bios.vendor)
1219
+ dmi->bios.vendor,
1220
+ sizeof(dmi->bios.vendor)
1221
);
1222
1223
windows_read_registry_string(
1224
HKEY_LOCAL_MACHINE,
1225
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1226
"BIOSVersion",
1256
- ds->hw.bios.version,
1257
- sizeof(ds->hw.bios.version)
1227
+ dmi->bios.version,
1228
+ sizeof(dmi->bios.version)
1229
);
1230
1231
windows_read_registry_string(
1232
HKEY_LOCAL_MACHINE,
1233
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1234
"BIOSReleaseDate",
1264
- ds->hw.bios.date,
1265
- sizeof(ds->hw.bios.date)
1235
+ dmi->bios.date,
1236
+ sizeof(dmi->bios.date)
1237
);
1238
1239
// Board information
1241
HKEY_LOCAL_MACHINE,
1242
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1243
"BaseBoardManufacturer",
1273
- ds->hw.board.vendor,
1274
- sizeof(ds->hw.board.vendor)
1244
+ dmi->board.vendor,
1245
+ sizeof(dmi->board.vendor)
1246
);
1247
1248
windows_read_registry_string(
1249
HKEY_LOCAL_MACHINE,
1250
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1251
"BaseBoardProduct",
1281
- ds->hw.board.name,
1282
- sizeof(ds->hw.board.name)
1252
+ dmi->board.name,
1253
+ sizeof(dmi->board.name)
1254
);
1255
1256
windows_read_registry_string(
1257
HKEY_LOCAL_MACHINE,
1258
"HARDWARE\\DESCRIPTION\\System\\BIOS",
1259
"BaseBoardVersion",
1289
- ds->hw.board.version,
1290
- sizeof(ds->hw.board.version)
1260
+ dmi->board.version,
1261
+ sizeof(dmi->board.version)
1262
+ );
1263
+
1264
+ // Base Board Serial
1265
+ windows_read_registry_string(
1266
+ HKEY_LOCAL_MACHINE,
1267
+ "HARDWARE\\DESCRIPTION\\System\\BIOS",
1268
+ "BaseBoardSerialNumber",
1269
+ dmi->board.serial,
1270
+ sizeof(dmi->board.serial)
1271
);
1272
+
1273
+ // Chassis Serial (might not be available in registry, but try anyway)
1274
+ windows_read_registry_string(
1275
+ HKEY_LOCAL_MACHINE,
1276
+ "HARDWARE\\DESCRIPTION\\System\\BIOS",
1277
+ "ChassisSerialNumber",
1278
+ dmi->chassis.serial,
1279
+ sizeof(dmi->chassis.serial)
1280
+ );
1281
+
1282
+ // Get BIOS boot mode (UEFI or Legacy)
1283
+ DWORD firmware_type = 0;
1284
+ if (GetFirmwareType(&firmware_type)) {
1285
+ switch (firmware_type) {
1286
+ case 1: // FirmwareTypeBios
1287
+ safecpy(dmi->bios.mode, "Legacy");
1288
+ break;
1289
+ case 2: // FirmwareTypeUefi
1290
+ safecpy(dmi->bios.mode, "UEFI");
1291
+ break;
1292
+ default:
1293
+ safecpy(dmi->bios.mode, "Unknown");
1294
+ }
1295
+ }
1296
+
1297
+ // Check if secure boot is enabled
1298
+ HKEY key;
1299
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State",
1300
+ 0, KEY_READ, &key) == ERROR_SUCCESS) {
1301
+ DWORD secure_boot_value = 0;
1302
+ DWORD size = sizeof(secure_boot_value);
1303
+ if (RegQueryValueExA(key, "UEFISecureBootEnabled", NULL, NULL,
1304
+ (LPBYTE)&secure_boot_value, &size) == ERROR_SUCCESS) {
1305
+ dmi->bios.secure_boot = (secure_boot_value != 0);
1306
+ }
1307
+ RegCloseKey(key);
1308
+ }
1309
}
1310
1311
// Main function to get hardware information
1295
-void os_dmi_info(DAEMON_STATUS_FILE *ds) {
1312
+void os_dmi_info_get(DMI_INFO *dmi) {
1313
+ if (!dmi) return;
1314
+
1315
// First try SMBIOS data through firmware table API
1297
- windows_get_smbios_info(ds);
1316
+ windows_get_smbios_info(dmi);
1317
1318
// Try registry as a fallback or to fill missing values
1300
- windows_get_registry_info(ds);
1319
+ windows_get_registry_info(dmi);
1320
+
1321
+ // Get asset tags if not set by SMBIOS
1322
+ if (!dmi->sys.asset_tag[0]) {
1323
+ windows_read_registry_string(
1324
+ HKEY_LOCAL_MACHINE,
1325
+ "HARDWARE\\DESCRIPTION\\System\\BIOS",
1326
+ "SystemAssetTag",
1327
+ dmi->sys.asset_tag,
1328
+ sizeof(dmi->sys.asset_tag)
1329
+ );
1330
+ }
1331
+
1332
+ if (!dmi->board.asset_tag[0]) {
1333
+ windows_read_registry_string(
1334
+ HKEY_LOCAL_MACHINE,
1335
+ "HARDWARE\\DESCRIPTION\\System\\BIOS",
1336
+ "BaseBoardAssetTag",
1337
+ dmi->board.asset_tag,
1338
+ sizeof(dmi->board.asset_tag)
1339
+ );
1340
+ }
1341
+
1342
+ if (!dmi->chassis.asset_tag[0]) {
1343
+ windows_read_registry_string(
1344
+ HKEY_LOCAL_MACHINE,
1345
+ "HARDWARE\\DESCRIPTION\\System\\BIOS",
1346
+ "ChassisAssetTag",
1347
+ dmi->chassis.asset_tag,
1348
+ sizeof(dmi->chassis.asset_tag)
1349
+ );
1350
+ }
1351
+
1352
+ // Check for Secure Boot - Read directly from registry, no external commands
1353
+ HKEY secureBootKey;
1354
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State",
1355
+ 0, KEY_READ, &secureBootKey) == ERROR_SUCCESS) {
1356
+ DWORD secure_boot = 0;
1357
+ DWORD size = sizeof(secure_boot);
1358
+ if (RegQueryValueExA(secureBootKey, "UEFISecureBootEnabled", NULL, NULL,
1359
+ (LPBYTE)&secure_boot, &size) == ERROR_SUCCESS) {
1360
+ dmi->bios.secure_boot = (secure_boot != 0);
1361
+ }
1362
+ RegCloseKey(secureBootKey);
1363
+ }
1364
1365
// If chassis type is not set or not a valid number, set a default
1303
- if (!ds->hw.chassis.type[0] || atoi(ds->hw.chassis.type) <= 0) {
1366
+ if (!dmi->chassis.type[0] || atoi(dmi->chassis.type) <= 0) {
1367
// Check common system names for laptops
1305
- if (strcasestr(ds->hw.product.name, "notebook") != NULL ||
1306
- strcasestr(ds->hw.product.name, "laptop") != NULL ||
1307
- strcasestr(ds->hw.product.name, "book") != NULL) {
1308
- safecpy(ds->hw.chassis.type, "9"); // Laptop
1368
+ if (strcasestr(dmi->product.name, "notebook") != NULL ||
1369
+ strcasestr(dmi->product.name, "laptop") != NULL ||
1370
+ strcasestr(dmi->product.name, "book") != NULL) {
1371
+ safecpy(dmi->chassis.type, "9"); // Laptop
1372
}
1373
// Check for servers
1311
- else if (strcasestr(ds->hw.product.name, "server") != NULL) {
1312
- safecpy(ds->hw.chassis.type, "17"); // Server
1374
+ else if (strcasestr(dmi->product.name, "server") != NULL) {
1375
+ safecpy(dmi->chassis.type, "17"); // Server
1376
}
1377
// Default to desktop
1378
else {
1316
- safecpy(ds->hw.chassis.type, "3"); // Desktop
1379
+ safecpy(dmi->chassis.type, "3"); // Desktop
1380
}
1381
}
1382
}
1383
1384
#else
1322
-void os_dmi_info(DAEMON_STATUS_FILE *ds) {
1323
- ;
1385
+void os_dmi_info_get(DMI_INFO *dmi) {
1386
+ // No implementation for this platform
1387
}
1388
#endif
1389
1390
// --------------------------------------------------------------------------------------------------------------------
1391
// public API
1392
1330
-void finalize_vendor_product_vm(DAEMON_STATUS_FILE *ds) {
1331
- if(ds->cloud_provider_type[0] && strcmp(ds->cloud_provider_type, "unknown") != 0)
1332
- safecpy(ds->hw.sys.vendor, ds->cloud_provider_type);
1333
-
1334
- if(ds->cloud_instance_type[0] && strcmp(ds->cloud_instance_type, "unknown") != 0)
1335
- safecpy(ds->hw.product.name, ds->cloud_instance_type);
1336
-
1337
- if(ds->virtualization[0] && strcmp(ds->virtualization, "none") != 0 && strcmp(ds->virtualization, "unknown") != 0)
1338
- safecpy(ds->hw.chassis.type, "vm");
1339
-}
1340
-
1341
-void fill_dmi_info(DAEMON_STATUS_FILE *ds) {
1342
- ds->hw.sys.vendor[0] = '\0';
1343
- ds->hw.product.name[0] = '\0';
1344
- ds->hw.product.version[0] = '\0';
1345
- ds->hw.product.sku[0] = '\0';
1346
- ds->hw.product.family[0] = '\0';
1347
- ds->hw.board.vendor[0] = '\0';
1348
- ds->hw.board.name[0] = '\0';
1349
- ds->hw.board.version[0] = '\0';
1350
- ds->hw.bios.vendor[0] = '\0';
1351
- ds->hw.bios.version[0] = '\0';
1352
- ds->hw.bios.date[0] = '\0';
1353
- ds->hw.bios.release[0] = '\0';
1354
- ds->hw.chassis.vendor[0] = '\0';
1355
- ds->hw.chassis.version[0] = '\0';
1356
- ds->hw.chassis.type[0] = '\0';
1357
-
1358
- os_dmi_info(ds);
1359
-
1360
- dmi_normalize_vendor_field(ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
1361
- dmi_normalize_vendor_field(ds->hw.board.vendor, sizeof(ds->hw.board.vendor));
1362
- dmi_normalize_vendor_field(ds->hw.chassis.vendor, sizeof(ds->hw.chassis.vendor));
1363
- dmi_normalize_vendor_field(ds->hw.bios.vendor, sizeof(ds->hw.bios.vendor));
1364
-
1365
- dmi_map_chassis_type(ds, atoi(ds->hw.chassis.type));
1366
-
1367
- // make sure we have a system vendor
1368
- if(!ds->hw.sys.vendor[0])
1369
- safecpy(ds->hw.sys.vendor, ds->hw.board.vendor);
1370
- if(!ds->hw.sys.vendor[0])
1371
- safecpy(ds->hw.sys.vendor, ds->hw.chassis.vendor);
1372
- if(!ds->hw.sys.vendor[0])
1373
- safecpy(ds->hw.sys.vendor, ds->hw.bios.vendor);
1374
- if(!ds->hw.sys.vendor[0] && strstr(ds->hw.product.name, "Raspberry") != NULL) {
1375
- safecpy(ds->hw.sys.vendor, "Raspberry");
1376
- safecpy(ds->hw.chassis.type, "mini-pc");
1377
- }
1378
- if(!ds->hw.sys.vendor[0] && (strstr(ds->hw.product.name, "VirtualMac") != NULL || strstr(ds->hw.board.name, "Apple") != NULL))
1379
- safecpy(ds->hw.sys.vendor, "Apple");
1380
- if(!ds->hw.sys.vendor[0])
1381
- safecpy(ds->hw.sys.vendor, "Unknown");
1382
-
1383
- // make sure we have a product name
1384
- if(!ds->hw.product.name[0])
1385
- safecpy(ds->hw.product.name, ds->hw.board.name);
1386
- if(!ds->hw.product.name[0])
1387
- safecpy(ds->hw.product.name, "Unknown");
1388
-
1389
- // make sure we have a chassis type
1390
- if(!ds->hw.chassis.type[0])
1391
- safecpy(ds->hw.chassis.type, "Unknown");
1392
-
1393
- // make sure the cloud provider and cloud instance loaded from system-info.sh are preferred
1394
- finalize_vendor_product_vm(ds);
1393
+void dmi_info_init(DMI_INFO *dmi) {
1394
+ if (!dmi) return;
1395
+
1396
+ // System information
1397
+ dmi->sys.vendor[0] = '\0';
1398
+ dmi->sys.serial[0] = '\0';
1399
+ dmi->sys.uuid[0] = '\0';
1400
+ dmi->sys.asset_tag[0] = '\0';
1401
+
1402
+ // Product information
1403
+ dmi->product.name[0] = '\0';
1404
+ dmi->product.version[0] = '\0';
1405
+ dmi->product.sku[0] = '\0';
1406
+ dmi->product.family[0] = '\0';
1407
+
1408
+ // Board information
1409
+ dmi->board.vendor[0] = '\0';
1410
+ dmi->board.name[0] = '\0';
1411
+ dmi->board.version[0] = '\0';
1412
+ dmi->board.serial[0] = '\0';
1413
+ dmi->board.asset_tag[0] = '\0';
1414
+
1415
+ // BIOS information
1416
+ dmi->bios.vendor[0] = '\0';
1417
+ dmi->bios.version[0] = '\0';
1418
+ dmi->bios.date[0] = '\0';
1419
+ dmi->bios.release[0] = '\0';
1420
+ dmi->bios.mode[0] = '\0';
1421
+ dmi->bios.secure_boot = false;
1422
+
1423
+ // Chassis information
1424
+ dmi->chassis.vendor[0] = '\0';
1425
+ dmi->chassis.version[0] = '\0';
1426
+ dmi->chassis.type[0] = '\0';
1427
+ dmi->chassis.serial[0] = '\0';
1428
+ dmi->chassis.asset_tag[0] = '\0';
1429
}