| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "libnetdata/libnetdata.h" |
| 4 | |
| 5 | #if defined(OS_WINDOWS) |
| 6 | bool os_hostname(char *dst, size_t dst_size, const char *filesystem_root __maybe_unused) { |
| 7 | WCHAR wbuf[HOST_NAME_MAX * 4 + 1]; |
| 8 | char buf[HOST_NAME_MAX * 4 + 1]; |
| 9 | DWORD size = _countof(wbuf); |
| 10 | bool success = false; |
| 11 | |
| 12 | // First try DNS hostname |
| 13 | if (GetComputerNameExW(ComputerNameDnsHostname, wbuf, &size)) { |
| 14 | success = true; |
| 15 | } |
| 16 | // Then try NetBIOS name |
| 17 | else { |
| 18 | size = _countof(wbuf); |
| 19 | if (GetComputerNameW(wbuf, &size)) { |
| 20 | success = true; |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | if (success) { |
| 25 | // Convert UTF-16 to UTF-8 |
| 26 | int utf8_size = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, NULL); |
| 27 | if (utf8_size > 0 && utf8_size <= (int)sizeof(buf)) { |
| 28 | WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, utf8_size, NULL, NULL); |
| 29 | } |
| 30 | else { |
| 31 | success = false; |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | if (!success) { |
| 36 | // Try getting the machine GUID first |
| 37 | HKEY hKey; |
| 38 | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { |
| 39 | WCHAR guidW[64]; |
| 40 | DWORD guidSize = sizeof(guidW); |
| 41 | DWORD type = REG_SZ; |
| 42 | |
| 43 | if (RegQueryValueExW(hKey, L"MachineGuid", NULL, &type, (LPBYTE)guidW, &guidSize) == ERROR_SUCCESS) { |
| 44 | // Convert GUID to UTF-8 |
| 45 | if (WideCharToMultiByte(CP_UTF8, 0, guidW, -1, buf, sizeof(buf), NULL, NULL) > 0) { |
| 46 | success = true; |
| 47 | } |
| 48 | } |
| 49 | RegCloseKey(hKey); |
| 50 | } |
| 51 | |
| 52 | if (!success) { |
| 53 | // If machine GUID fails, try getting volume serial number of C: drive |
| 54 | WCHAR rootPath[] = L"C:\\"; |
| 55 | DWORD serialNumber; |
| 56 | if (GetVolumeInformationW(rootPath, NULL, 0, &serialNumber, NULL, NULL, NULL, 0)) { |
| 57 | snprintf(buf, sizeof(buf), "host%08lx", (long unsigned)serialNumber); |
| 58 | success = true; |
| 59 | } |
| 60 | else { |
| 61 | // Last resort: use process ID |
| 62 | snprintf(buf, sizeof(buf), "host%lu", (long unsigned)GetCurrentProcessId()); |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | char *hostname = trim(buf); |
| 68 | rrdlabels_sanitize_value(dst, hostname, dst_size); |
| 69 | return *dst != '\0'; |
| 70 | } |
| 71 | #else // !OS_WINDOWS |
| 72 | |
| 73 | #ifdef HAVE_LIBICONV |
| 74 | #include <iconv.h> |
| 75 | |
| 76 | static const char *get_current_locale(void) { |
| 77 | const char *locale = getenv("LC_ALL"); // LC_ALL overrides all other locale settings |
| 78 | |
| 79 | if (!locale || !*locale) { |
| 80 | locale = getenv("LC_CTYPE"); // Check LC_CTYPE for character encoding |
| 81 | |
| 82 | if (!locale || !*locale) |
| 83 | locale = getenv("LANG"); // Fallback to LANG |
| 84 | } |
| 85 | |
| 86 | return locale; |
| 87 | } |
| 88 | |
| 89 | static const char *get_encoding_from_locale(const char *locale) { |
| 90 | if(!locale || !*locale) |
| 91 | return NULL; |
| 92 | |
| 93 | const char *dot = strchr(locale, '.'); |
| 94 | if (dot) |
| 95 | return dot + 1; |
| 96 | |
| 97 | return locale; |
| 98 | } |
| 99 | |
| 100 | // Function to convert from a source encoding to UTF-8 |
| 101 | static bool iconv_convert_to_utf8(const char *input, const char *src_encoding, char *output, size_t output_size) { |
| 102 | iconv_t cd = iconv_open("UTF-8", src_encoding); |
| 103 | if (cd == (iconv_t)-1) { |
| 104 | int i = errno; |
| 105 | return false; |
| 106 | } |
| 107 | |
| 108 | char *input_ptr = (char *)input; // iconv() may modify this pointer |
| 109 | char *output_ptr = output; // iconv() modifies this pointer |
| 110 | size_t input_len = strlen(input); |
| 111 | size_t output_len = output_size; |
| 112 | |
| 113 | // Perform the conversion |
| 114 | if (iconv(cd, &input_ptr, &input_len, &output_ptr, &output_len) == (size_t)-1) { |
| 115 | iconv_close(cd); |
| 116 | return false; |
| 117 | } |
| 118 | |
| 119 | // Null-terminate the output string |
| 120 | *output_ptr = '\0'; |
| 121 | |
| 122 | iconv_close(cd); |
| 123 | return true; |
| 124 | } |
| 125 | #endif |
| 126 | |
| 127 | bool os_hostname(char *dst, size_t dst_size, const char *filesystem_root) { |
| 128 | *dst = '\0'; |
| 129 | |
| 130 | char buf[HOST_NAME_MAX * 4 + 1]; |
| 131 | *buf = '\0'; |
| 132 | |
| 133 | if (filesystem_root && *filesystem_root) { |
| 134 | char filename[FILENAME_MAX + 1]; |
| 135 | snprintfz(filename, FILENAME_MAX, "%s/etc/hostname", netdata_configured_host_prefix); |
| 136 | |
| 137 | if (read_txt_file(filename, buf, sizeof(buf))) |
| 138 | *buf = '\0'; |
| 139 | } |
| 140 | |
| 141 | if(!*buf && gethostname(buf, sizeof(buf)) != 0) |
| 142 | snprintf(buf, sizeof(buf), "host%ld", gethostid()); |
| 143 | |
| 144 | char *original_hostname = trim(buf); |
| 145 | |
| 146 | #ifdef HAVE_LIBICONV |
| 147 | const char *locale = get_current_locale(); |
| 148 | if (locale && *locale) { |
| 149 | char utf8_output[HOST_NAME_MAX * 4 + 1] = ""; |
| 150 | if(iconv_convert_to_utf8(original_hostname, get_encoding_from_locale(locale), utf8_output, sizeof(utf8_output))) { |
| 151 | rrdlabels_sanitize_value(dst, trim(utf8_output), dst_size); |
| 152 | return *dst != '\0'; |
| 153 | } |
| 154 | } |
| 155 | #endif |
| 156 | |
| 157 | rrdlabels_sanitize_value(dst, original_hostname, dst_size); |
| 158 | return *dst != '\0'; |
| 159 | } |
| 160 | |
| 161 | #endif // !OS_WINDOWS |