| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "status-file-dmi.h" |
| 4 | #include "status-file-product.h" |
| 5 | |
| 6 | static void dmi_normalize_vendor_field(char *buf, size_t buf_size) { |
| 7 | if(!buf || !buf_size) return; |
| 8 | |
| 9 | struct { |
| 10 | const char *found; |
| 11 | const char *replace; |
| 12 | } vendors[] = { |
| 13 | {"QEMU", "KVM"}, |
| 14 | |
| 15 | // Major vendors with multiple variations |
| 16 | {"AMD Corporation", "AMD"}, |
| 17 | {"Advanced Micro Devices, Inc.", "AMD"}, |
| 18 | |
| 19 | {"AMI Corp.", "AMI"}, |
| 20 | {"AMI Corporation", "AMI"}, |
| 21 | {"American Megatrends", "AMI"}, |
| 22 | {"American Megatrends Inc.", "AMI"}, |
| 23 | {"American Megatrends International", "AMI"}, |
| 24 | {"American Megatrends International, LLC.", "AMI"}, |
| 25 | |
| 26 | {"AOPEN", "AOpen"}, |
| 27 | {"AOPEN Inc.", "AOpen"}, |
| 28 | |
| 29 | {"Apache Software Foundation", "Apache"}, |
| 30 | |
| 31 | {"Apple Inc.", "Apple"}, |
| 32 | |
| 33 | {"ASRock Industrial", "ASRock"}, |
| 34 | {"ASRockRack", "ASRock"}, |
| 35 | {"AsrockRack", "ASRock"}, |
| 36 | |
| 37 | {"ASUS", "ASUSTeK"}, |
| 38 | {"ASUSTeK COMPUTER INC.", "ASUSTeK"}, |
| 39 | {"ASUSTeK COMPUTER INC. (Licensed from AMI)", "ASUSTeK"}, |
| 40 | {"ASUSTeK Computer INC.", "ASUSTeK"}, |
| 41 | {"ASUSTeK Computer Inc.", "ASUSTeK"}, |
| 42 | {"ASUSTek Computer INC.", "ASUSTeK"}, |
| 43 | |
| 44 | {"Apache Software Foundation", "Apache"}, |
| 45 | |
| 46 | {"BESSTAR (HK) LIMITED", "Besstar"}, |
| 47 | {"BESSTAR TECH", "Besstar"}, |
| 48 | {"BESSTAR TECH LIMITED", "Besstar"}, |
| 49 | {"BESSTAR Tech", "Besstar"}, |
| 50 | |
| 51 | {"CHUWI", "Chuwi"}, |
| 52 | {"CHUWI Innovation And Technology(ShenZhen)co.,Ltd", "Chuwi"}, |
| 53 | |
| 54 | {"Cisco Systems Inc", "Cisco"}, |
| 55 | {"Cisco Systems, Inc.", "Cisco"}, |
| 56 | |
| 57 | {"DELL", "Dell"}, |
| 58 | {"Dell Computer Corporation", "Dell"}, |
| 59 | {"Dell Inc.", "Dell"}, |
| 60 | {"Dell EMC", "Dell"}, |
| 61 | |
| 62 | {"FUJITSU", "Fujitsu"}, |
| 63 | {"FUJITSU CLIENT COMPUTING LIMITED", "Fujitsu"}, |
| 64 | {"FUJITSU SIEMENS", "Fujitsu"}, |
| 65 | {"FUJITSU SIEMENS // Phoenix Technologies Ltd.", "Fujitsu"}, |
| 66 | {"FUJITSU // American Megatrends Inc.", "Fujitsu"}, |
| 67 | {"FUJITSU // American Megatrends International, LLC.", "Fujitsu"}, |
| 68 | {"FUJITSU // Insyde Software Corp.", "Fujitsu"}, |
| 69 | {"FUJITSU // Phoenix Technologies Ltd.", "Fujitsu"}, |
| 70 | |
| 71 | {"GIGABYTE", "Gigabyte"}, |
| 72 | {"Giga Computing", "Gigabyte"}, |
| 73 | {"Gigabyte Technology Co., Ltd.", "Gigabyte"}, |
| 74 | {"Gigabyte Tecohnology Co., Ltd.", "Gigabyte"}, |
| 75 | |
| 76 | {"GOOGLE", "Google"}, |
| 77 | {"Google Inc", "Google"}, |
| 78 | |
| 79 | {"HC Technology.,Ltd.", "HC Tech"}, |
| 80 | |
| 81 | {"HP-Pavilion", "HP"}, |
| 82 | {"HPE", "HP"}, |
| 83 | {"Hewlett Packard Enterprise", "HP"}, |
| 84 | {"Hewlett-Packard", "HP"}, |
| 85 | |
| 86 | {"HUAWEI", "Huawei"}, |
| 87 | {"Huawei Technologies Co., Ltd.", "Huawei"}, |
| 88 | |
| 89 | {"IBM Corp.", "IBM"}, |
| 90 | |
| 91 | {"IceWhale Technology Co.,Ltd.", "IceWhale"}, |
| 92 | |
| 93 | {"INSYDE", "Insyde"}, |
| 94 | {"INSYDE Corp.", "Insyde"}, |
| 95 | {"Insyde Corp.", "Insyde"}, |
| 96 | |
| 97 | {"INTEL", "Intel"}, |
| 98 | {"INTEL Corporation", "Intel"}, |
| 99 | {"Intel Corp.", "Intel"}, |
| 100 | {"Intel Corporation", "Intel"}, |
| 101 | {"Intel corporation", "Intel"}, |
| 102 | {"Intel(R) Client Systems", "Intel"}, |
| 103 | {"Intel(R) Corporation", "Intel"}, |
| 104 | |
| 105 | {"LENOVO", "Lenovo"}, |
| 106 | {"LNVO", "Lenovo"}, |
| 107 | |
| 108 | {"Shenzhen Meigao Electronic Equipment Co.,Ltd", "Meigao"}, |
| 109 | {"Micro Computer (HK) Tech Limited", "Micro Computer"}, |
| 110 | {"Micro Computer(HK) Tech Limited", "Micro Computer"}, |
| 111 | |
| 112 | {"MICRO-STAR INTERNATIONAL CO., LTD", "MSI"}, |
| 113 | {"MICRO-STAR INTERNATIONAL CO.,LTD", "MSI"}, |
| 114 | {"MSI", "MSI"}, |
| 115 | {"Micro-Star International Co., Ltd", "MSI"}, |
| 116 | {"Micro-Star International Co., Ltd.", "MSI"}, |
| 117 | |
| 118 | {"MICROSOFT", "Microsoft"}, |
| 119 | {"Microsoft Corporation", "Microsoft"}, |
| 120 | |
| 121 | {"nVIDIA", "NVIDIA"}, |
| 122 | |
| 123 | {"OPENSTACK", "OpenStack"}, |
| 124 | {"OpenStack Foundation", "OpenStack"}, |
| 125 | |
| 126 | {"ORACLE CORPORATI", "Oracle"}, |
| 127 | {"Oracle Corporation", "Oracle"}, |
| 128 | {"innotek GmbH", "Oracle"}, |
| 129 | |
| 130 | {"Phoenix Technologies LTD", "Phoenix"}, |
| 131 | {"Phoenix Technologies Ltd", "Phoenix"}, |
| 132 | {"Phoenix Technologies Ltd.", "Phoenix"}, |
| 133 | {"Phoenix Technologies, LTD", "Phoenix"}, |
| 134 | |
| 135 | {"QNAP Systems, Inc.", "QNAP"}, |
| 136 | |
| 137 | {"QUANTA", "Quanta"}, |
| 138 | {"Quanta Cloud Technology Inc.", "Quanta"}, |
| 139 | {"Quanta Computer Inc", "Quanta"}, |
| 140 | {"Quanta Computer Inc.", "Quanta"}, |
| 141 | |
| 142 | {"RED HAT", "Red Hat"}, |
| 143 | |
| 144 | {"SAMSUNG ELECTRONICS CO., LTD.", "Samsung"}, |
| 145 | |
| 146 | {"SUN MICROSYSTEMS", "Sun"}, |
| 147 | |
| 148 | {"SuperMicro", "Supermicro"}, |
| 149 | {"Supermicro Corporation", "Supermicro"}, |
| 150 | |
| 151 | {"SYNOLOGY", "Synology"}, |
| 152 | {"Synology Inc.", "Synology"}, |
| 153 | |
| 154 | {"TYAN", "Tyan"}, |
| 155 | {"TYAN Computer Corporation", "Tyan"}, |
| 156 | {"Tyan Computer Corporation", "Tyan"}, |
| 157 | {"$(TYAN_SYSTEM_MANUFACTURER)", "Tyan"}, |
| 158 | |
| 159 | {"VMware", "VMware"}, |
| 160 | {"VMware, Inc.", "VMware"}, |
| 161 | |
| 162 | {"XIAOMI", "Xiaomi"}, |
| 163 | |
| 164 | {"ZOTAC", "Zotac"}, |
| 165 | {"Motherboard by ZOTAC", "Zotac"} |
| 166 | }; |
| 167 | |
| 168 | for (size_t i = 0; i < _countof(vendors); i++) { |
| 169 | if (strcasecmp(buf, vendors[i].found) == 0) { |
| 170 | strcatz(buf, 0, vendors[i].replace, buf_size); |
| 171 | break; |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | static bool dmi_is_virtual_machine(const DMI_INFO *dmi) { |
| 177 | if(!dmi) return false; |
| 178 | |
| 179 | const char *vm_indicators[] = { |
| 180 | "Virt", "KVM", "vServer", "Cloud", "Hyper", "Droplet", |
| 181 | "Compute ", // with a space to not match "Computer" |
| 182 | "HVM domU", "Parallels", "(i440FX", "(q35", "OpenStack", "QEMU", |
| 183 | "VMWare", "DigitalOcean", "Oracle", "Linode", "Amazon EC2" |
| 184 | }; |
| 185 | |
| 186 | const char *strs_to_check[] = { |
| 187 | dmi->product.name, |
| 188 | dmi->product.family, |
| 189 | dmi->sys.vendor, |
| 190 | dmi->board.name, |
| 191 | }; |
| 192 | |
| 193 | for (size_t i = 0; i < _countof(strs_to_check); i++) { |
| 194 | if (!strs_to_check[i] || !strs_to_check[i][0]) |
| 195 | continue; |
| 196 | |
| 197 | for (size_t j = 0; j < _countof(vm_indicators); j++) { |
| 198 | if (strcasestr(strs_to_check[i], vm_indicators[j]) != NULL) |
| 199 | return true; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | return false; |
| 204 | } |
| 205 | |
| 206 | static const char *dmi_chassis_type_to_string(int chassis_type) { |
| 207 | // Original info from SMBIOS |
| 208 | // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf |
| 209 | // see also inxi: https://github.com/smxi/inxi/blob/master/inxi |
| 210 | |
| 211 | // we categorize chassis types as: |
| 212 | // 1. desktop |
| 213 | // 2. laptop |
| 214 | // 3. server |
| 215 | // 4. mini-pc |
| 216 | // 5. unknown |
| 217 | // elsewhere we mark them also as "vm" (which is preferred over this) |
| 218 | |
| 219 | switch(chassis_type) { |
| 220 | case 3: /* "desktop" */ |
| 221 | case 4: /* "low-profile-desktop" */ |
| 222 | case 6: /* "mini-tower-desktop" */ |
| 223 | case 7: /* "tower-desktop" */ |
| 224 | case 13: /* "all-in-one" */ |
| 225 | case 15: /* "space-saving-desktop" */ |
| 226 | case 24: /* "sealed-desktop" */ |
| 227 | case 26: /* "compact-pci" */ |
| 228 | return "desktop"; |
| 229 | |
| 230 | case 5: /* "pizza-box" - was 1U desktops and some laptops */ |
| 231 | case 8: /* "portable" */ |
| 232 | case 9: /* "laptop" */ |
| 233 | case 10: /* "notebook" */ |
| 234 | case 11: /* "hand-held" */ |
| 235 | case 12: /* "docking-station" */ |
| 236 | case 14: /* "sub-notebook" */ |
| 237 | case 16: /* "lunch-box" */ |
| 238 | case 30: /* "tablet" */ |
| 239 | case 31: /* "convertible" */ |
| 240 | case 32: /* "detachable" */ |
| 241 | return "laptop"; |
| 242 | |
| 243 | case 17: /* "main-server-chassis" */ |
| 244 | case 23: /* "rack-mount-server" */ |
| 245 | case 25: /* "multimount-chassis" */ |
| 246 | case 27: /* "advanced-tca" */ |
| 247 | case 28: /* "blade" */ |
| 248 | case 29: /* "blade-enclosure" */ |
| 249 | return "server"; |
| 250 | |
| 251 | case 33: /* "iot-gateway" */ |
| 252 | case 34: /* "embedded-pc" */ |
| 253 | case 35: /* "mini-pc" */ |
| 254 | case 36: /* "stick-pc" */ |
| 255 | return "mini-pc"; |
| 256 | |
| 257 | case 1: /* "other" */ |
| 258 | case 2: /* "unknown" */ |
| 259 | case 18: /* "expansion-chassis" */ |
| 260 | case 19: /* "sub-chassis" */ |
| 261 | case 20: /* "bus-expansion" */ |
| 262 | case 21: /* "peripheral" */ |
| 263 | case 22: /* "raid" */ |
| 264 | default: |
| 265 | return "unknown"; |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | // Check for active ECC memory controllers |
| 270 | static bool has_ecc_memory(void) { |
| 271 | #if defined(OS_LINUX) |
| 272 | char edac_path[FILENAME_MAX + 1]; |
| 273 | snprintfz(edac_path, FILENAME_MAX, "%s/sys/devices/system/edac/mc", netdata_configured_host_prefix ? netdata_configured_host_prefix : ""); |
| 274 | |
| 275 | DIR *dir = opendir(edac_path); |
| 276 | if (!dir) |
| 277 | return false; |
| 278 | |
| 279 | struct dirent *entry; |
| 280 | bool found_mc = false; |
| 281 | |
| 282 | while ((entry = readdir(dir))) { |
| 283 | // Look for "mc0", "mc1", etc. directories |
| 284 | if (strncmp(entry->d_name, "mc", 2) == 0 && isdigit(entry->d_name[2])) { |
| 285 | // Check for presence of ECC-related files in this mc directory |
| 286 | char mc_path[FILENAME_MAX + 1]; |
| 287 | snprintfz(mc_path, FILENAME_MAX, "%s/%s/ce_count", edac_path, entry->d_name); |
| 288 | |
| 289 | struct stat st; |
| 290 | if (stat(mc_path, &st) == 0) { |
| 291 | found_mc = true; |
| 292 | break; |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | closedir(dir); |
| 298 | return found_mc; |
| 299 | #else |
| 300 | return false; // Not implemented for this OS |
| 301 | #endif |
| 302 | } |
| 303 | |
| 304 | // Check for IPMI device |
| 305 | static bool has_ipmi(void) { |
| 306 | #if defined(OS_LINUX) |
| 307 | char ipmi_dev_path[FILENAME_MAX + 1]; |
| 308 | snprintfz(ipmi_dev_path, FILENAME_MAX, "%s/dev/ipmi0", netdata_configured_host_prefix ? netdata_configured_host_prefix : ""); |
| 309 | struct stat ipmi_stat; |
| 310 | return (stat(ipmi_dev_path, &ipmi_stat) == 0); |
| 311 | #else |
| 312 | return false; // Not implemented for this OS |
| 313 | #endif |
| 314 | } |
| 315 | |
| 316 | // Check for multiple CPU sockets |
| 317 | static bool has_multiple_cpu_sockets(void) { |
| 318 | #if defined(OS_LINUX) |
| 319 | char cpu_path[FILENAME_MAX + 1]; |
| 320 | snprintfz(cpu_path, FILENAME_MAX, "%s/sys/devices/system/cpu", netdata_configured_host_prefix ? netdata_configured_host_prefix : ""); |
| 321 | |
| 322 | DIR *dir = opendir(cpu_path); |
| 323 | if (!dir) |
| 324 | return false; |
| 325 | |
| 326 | DICTIONARY *physical_ids = dictionary_create(DICT_OPTION_SINGLE_THREADED); |
| 327 | struct dirent *entry; |
| 328 | |
| 329 | while ((entry = readdir(dir))) { |
| 330 | // Check for cpu directories (cpu0, cpu1, etc.) |
| 331 | if (strncmp(entry->d_name, "cpu", 3) == 0 && isdigit(entry->d_name[3])) { |
| 332 | char topology_path[FILENAME_MAX + 1]; |
| 333 | char physical_id[64]; |
| 334 | |
| 335 | // Read the physical_package_id file for this CPU |
| 336 | snprintfz(topology_path, FILENAME_MAX, "%s/%s/topology/physical_package_id", |
| 337 | cpu_path, entry->d_name); |
| 338 | |
| 339 | if (read_txt_file(topology_path, physical_id, sizeof(physical_id)) == 0) { |
| 340 | dictionary_set(physical_ids, physical_id, NULL, 0); |
| 341 | } |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | closedir(dir); |
| 346 | |
| 347 | unsigned int socket_count = dictionary_entries(physical_ids); |
| 348 | dictionary_destroy(physical_ids); |
| 349 | |
| 350 | return (socket_count > 1); |
| 351 | #else |
| 352 | return false; // Not implemented for this OS |
| 353 | #endif |
| 354 | } |
| 355 | |
| 356 | // Main function to check for server hardware indicators |
| 357 | static bool is_server_hardware(void) { |
| 358 | // Check each server indicator |
| 359 | if (has_ecc_memory()) |
| 360 | return true; |
| 361 | |
| 362 | if (has_ipmi()) |
| 363 | return true; |
| 364 | |
| 365 | if (has_multiple_cpu_sockets()) |
| 366 | return true; |
| 367 | |
| 368 | return false; // No server indicators found |
| 369 | } |
| 370 | |
| 371 | void product_name_vendor_type(DAEMON_STATUS_FILE *ds) { |
| 372 | char *force_type = NULL; |
| 373 | |
| 374 | if(ds->cloud_provider_type[0] && strcasecmp(ds->cloud_provider_type, "unknown") != 0) |
| 375 | safecpy(ds->product.vendor, ds->cloud_provider_type); |
| 376 | else { |
| 377 | // copy one of the names found in DMI |
| 378 | if(ds->hw.sys.vendor[0]) |
| 379 | safecpy(ds->product.vendor, ds->hw.sys.vendor); |
| 380 | else if(ds->hw.board.vendor[0]) |
| 381 | safecpy(ds->product.vendor, ds->hw.board.vendor); |
| 382 | else if(ds->hw.chassis.vendor[0]) |
| 383 | safecpy(ds->product.vendor, ds->hw.chassis.vendor); |
| 384 | else if(ds->hw.bios.vendor[0]) |
| 385 | safecpy(ds->product.vendor, ds->hw.bios.vendor); |
| 386 | |
| 387 | // derive the vendor from other DMI fields |
| 388 | if(!ds->product.vendor[0]) { |
| 389 | if(strcasestr(ds->hw.product.name, "VirtualMac") != NULL || |
| 390 | (strcasestr(ds->hw.board.name, "Apple") != NULL && |
| 391 | strcasestr(ds->hw.board.name, "Virtual") != NULL)) { |
| 392 | safecpy(ds->product.vendor, "Apple"); |
| 393 | force_type = "vm"; |
| 394 | } |
| 395 | else if(strcasestr(ds->hw.product.name, "NVIDIA") != NULL && |
| 396 | strcasestr(ds->hw.product.name, "Kit") != NULL) { |
| 397 | safecpy(ds->product.vendor, "NVIDIA"); |
| 398 | force_type = "mini-pc"; |
| 399 | } |
| 400 | else if(strcasestr(ds->hw.product.name, "Raspberry") != NULL) { |
| 401 | safecpy(ds->product.vendor, "Raspberry"); |
| 402 | force_type = "mini-pc"; |
| 403 | } |
| 404 | else if(strcasestr(ds->hw.product.name, "ODROID") != NULL) { |
| 405 | safecpy(ds->product.vendor, "Odroid"); |
| 406 | force_type = "mini-pc"; |
| 407 | } |
| 408 | else if(strcasestr(ds->hw.product.name, "BananaPi") != NULL || |
| 409 | strcasestr(ds->hw.product.name, "Banana Pi") != NULL) { |
| 410 | safecpy(ds->product.vendor, "BananaPi"); |
| 411 | force_type = "mini-pc"; |
| 412 | } |
| 413 | else if(strcasestr(ds->hw.product.name, "OrangePi") != NULL || |
| 414 | strcasestr(ds->hw.product.name, "Orange Pi") != NULL) { |
| 415 | safecpy(ds->product.vendor, "OrangePi"); |
| 416 | force_type = "mini-pc"; |
| 417 | } |
| 418 | } |
| 419 | |
| 420 | if(!ds->product.vendor[0]) |
| 421 | safecpy(ds->product.vendor, "unknown"); |
| 422 | else |
| 423 | dmi_normalize_vendor_field(ds->product.vendor, sizeof(ds->product.vendor)); |
| 424 | } |
| 425 | |
| 426 | if (!force_type && |
| 427 | (strcasestr(ds->product.vendor, "Raspberry") != NULL || |
| 428 | strcasestr(ds->product.vendor, "BananaPi") != NULL || |
| 429 | strcasestr(ds->product.vendor, "OrangePi") != NULL || |
| 430 | strcasestr(ds->product.vendor, "ODROID") != NULL)) { |
| 431 | force_type = "mini-pc"; |
| 432 | } |
| 433 | |
| 434 | if(ds->cloud_instance_type[0] && strcasecmp(ds->cloud_instance_type, "unknown") != 0) |
| 435 | safecpy(ds->product.name, ds->cloud_instance_type); |
| 436 | else { |
| 437 | // copy the product family |
| 438 | size_t len = strcatz(ds->product.name, 0, ds->hw.product.family, sizeof(ds->product.name)); |
| 439 | |
| 440 | // append the product name, if it is not included already |
| 441 | if(ds->hw.product.name[0] && !strcasestr(ds->product.name, ds->hw.product.name)) { |
| 442 | if(ds->product.name[0]) { |
| 443 | bool includes_family = strcasestr(ds->hw.product.name, ds->hw.product.family) != NULL; |
| 444 | |
| 445 | if(includes_family) { |
| 446 | // the product name includes the product family we have in buf |
| 447 | // we can clear the family and add only the product name |
| 448 | len = 0; |
| 449 | } |
| 450 | else { |
| 451 | // the product name is not included in the product family |
| 452 | // we append a separator, and later the name |
| 453 | len = strcatz(ds->product.name, len, " / ", sizeof(ds->product.name)); |
| 454 | } |
| 455 | } |
| 456 | |
| 457 | len = strcatz(ds->product.name, len, ds->hw.product.name, sizeof(ds->product.name)); |
| 458 | } |
| 459 | |
| 460 | // append the board name, if it is not included already |
| 461 | if(ds->hw.board.name[0] && !strcasestr(ds->product.name, ds->hw.board.name)) { |
| 462 | if(ds->product.name[0]) { |
| 463 | bool includes_family = !ds->hw.product.family[0] || strcasestr(ds->hw.board.name, ds->hw.product.family) != NULL; |
| 464 | bool includes_product = !ds->hw.product.name[0] || strcasestr(ds->hw.board.name, ds->hw.product.name) != NULL; |
| 465 | |
| 466 | if(includes_family && includes_product) { |
| 467 | // the board name includes both the product and the family |
| 468 | // we can clear buf and add only the board name |
| 469 | len = 0; |
| 470 | } |
| 471 | else { |
| 472 | // the board name is not included in buf |
| 473 | // we append a separator, and later the name |
| 474 | len = strcatz(ds->product.name, len, " / ", sizeof(ds->product.name)); |
| 475 | } |
| 476 | } |
| 477 | |
| 478 | len = strcatz(ds->product.name, len, ds->hw.board.name, sizeof(ds->product.name)); |
| 479 | } |
| 480 | |
| 481 | if(!ds->product.name[0]) |
| 482 | safecpy(ds->product.name, "unknown"); |
| 483 | } |
| 484 | |
| 485 | if(ds->virtualization[0] && strcasecmp(ds->virtualization, "none") != 0 && strcasecmp(ds->virtualization, "unknown") != 0) |
| 486 | safecpy(ds->product.type, "vm"); |
| 487 | else if(force_type) |
| 488 | safecpy(ds->product.type, force_type); |
| 489 | else if(dmi_is_virtual_machine(&ds->hw)) |
| 490 | safecpy(ds->product.type, "vm"); |
| 491 | else if(is_server_hardware()) |
| 492 | safecpy(ds->product.type, "server"); |
| 493 | else { |
| 494 | char *end = NULL; |
| 495 | int type = (int)strtol(ds->hw.chassis.type, &end, 10); |
| 496 | if(type && (!end || !*end)) |
| 497 | safecpy(ds->product.type, dmi_chassis_type_to_string(type)); |
| 498 | else |
| 499 | safecpy(ds->product.type, "unknown"); |
| 500 | } |
| 501 | } |