MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1062 lines 34 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <errno.h> 7 8#ifdef _WIN32 9#define WIN32_LEAN_AND_MEAN 10#include <winsock2.h> 11#include <ws2tcpip.h> 12#include <windows.h> 13#include <iphlpapi.h> 14#include <lmcons.h> 15#ifdef _MSC_VER 16#pragma comment(lib, "iphlpapi.lib") 17#pragma comment(lib, "ws2_32.lib") 18#endif 19#else 20#include <sys/resource.h> 21#include <sys/utsname.h> 22#include <pwd.h> 23#include <dlfcn.h> 24#include <ifaddrs.h> 25#include <net/if.h> 26#include <arpa/inet.h> 27#include <sys/socket.h> 28#ifdef __APPLE__ 29#include <net/if_dl.h> 30#include <sys/sysctl.h> 31#include <mach/mach.h> 32#include <mach/mach_host.h> 33#elif defined(__linux__) 34#include <netpacket/packet.h> 35#include <sys/sysinfo.h> 36#endif 37#endif 38 39#include "ant.h" 40#include "errors.h" 41#include "internal.h" 42#include "modules/symbol.h" 43 44#ifdef _WIN32 45#define OS_EOL "\r\n" 46#define OS_DEVNULL "\\\\.\\nul" 47#else 48#define OS_EOL "\n" 49#define OS_DEVNULL "/dev/null" 50#endif 51 52static ant_value_t os_arch(ant_t *js, ant_value_t *args, int nargs) { 53 (void)args; (void)nargs; 54#if defined(__x86_64__) || defined(_M_X64) 55 return js_mkstr(js, "x64", 3); 56#elif defined(__i386__) || defined(_M_IX86) 57 return js_mkstr(js, "ia32", 4); 58#elif defined(__aarch64__) || defined(_M_ARM64) 59 return js_mkstr(js, "arm64", 5); 60#elif defined(__arm__) || defined(_M_ARM) 61 return js_mkstr(js, "arm", 3); 62#elif defined(__riscv) && __riscv_xlen == 64 63 return js_mkstr(js, "riscv64", 7); 64#elif defined(__ppc64__) || defined(__PPC64__) 65 return js_mkstr(js, "ppc64", 5); 66#elif defined(__s390x__) 67 return js_mkstr(js, "s390x", 5); 68#elif defined(__mips64) 69 return js_mkstr(js, "mips64", 6); 70#elif defined(__mips__) 71 return js_mkstr(js, "mipsel", 6); 72#elif defined(__loongarch64) 73 return js_mkstr(js, "loong64", 7); 74#else 75 return js_mkstr(js, "unknown", 7); 76#endif 77} 78 79static ant_value_t os_platform(ant_t *js, ant_value_t *args, int nargs) { 80 (void)args; (void)nargs; 81#if defined(__APPLE__) 82 return js_mkstr(js, "darwin", 6); 83#elif defined(__linux__) 84 return js_mkstr(js, "linux", 5); 85#elif defined(_WIN32) || defined(_WIN64) 86 return js_mkstr(js, "win32", 5); 87#elif defined(__FreeBSD__) 88 return js_mkstr(js, "freebsd", 7); 89#elif defined(__OpenBSD__) 90 return js_mkstr(js, "openbsd", 7); 91#elif defined(__sun) 92 return js_mkstr(js, "sunos", 5); 93#elif defined(_AIX) 94 return js_mkstr(js, "aix", 3); 95#else 96 return js_mkstr(js, "unknown", 7); 97#endif 98} 99 100static ant_value_t os_type(ant_t *js, ant_value_t *args, int nargs) { 101 (void)args; (void)nargs; 102#if defined(__APPLE__) 103 return js_mkstr(js, "Darwin", 6); 104#elif defined(__linux__) 105 return js_mkstr(js, "Linux", 5); 106#elif defined(_WIN32) || defined(_WIN64) 107 return js_mkstr(js, "Windows_NT", 10); 108#elif defined(__FreeBSD__) 109 return js_mkstr(js, "FreeBSD", 7); 110#elif defined(__OpenBSD__) 111 return js_mkstr(js, "OpenBSD", 7); 112#else 113 return js_mkstr(js, "Unknown", 7); 114#endif 115} 116 117static ant_value_t os_release(ant_t *js, ant_value_t *args, int nargs) { 118 (void)args; (void)nargs; 119#ifdef _WIN32 120 OSVERSIONINFOA osvi; 121 ZeroMemory(&osvi, sizeof(OSVERSIONINFOA)); 122 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); 123 #pragma GCC diagnostic push 124 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 125 if (GetVersionExA(&osvi)) { 126 #pragma GCC diagnostic pop 127 char release[64]; 128 snprintf(release, sizeof(release), "%lu.%lu.%lu", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); 129 return js_mkstr(js, release, strlen(release)); 130 } 131 return js_mkstr(js, "", 0); 132#else 133 struct utsname info; 134 if (uname(&info) == 0) { 135 return js_mkstr(js, info.release, strlen(info.release)); 136 } 137 return js_mkstr(js, "", 0); 138#endif 139} 140 141static ant_value_t os_version(ant_t *js, ant_value_t *args, int nargs) { 142 (void)args; (void)nargs; 143#ifdef _WIN32 144 OSVERSIONINFOA osvi; 145 ZeroMemory(&osvi, sizeof(OSVERSIONINFOA)); 146 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); 147 #pragma GCC diagnostic push 148 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 149 if (GetVersionExA(&osvi)) { 150 #pragma GCC diagnostic pop 151 char version[256]; 152 snprintf(version, sizeof(version), "Windows %lu.%lu", osvi.dwMajorVersion, osvi.dwMinorVersion); 153 return js_mkstr(js, version, strlen(version)); 154 } 155 return js_mkstr(js, "", 0); 156#else 157 struct utsname info; 158 if (uname(&info) == 0) { 159 return js_mkstr(js, info.version, strlen(info.version)); 160 } 161 return js_mkstr(js, "", 0); 162#endif 163} 164 165static ant_value_t os_machine(ant_t *js, ant_value_t *args, int nargs) { 166 (void)args; (void)nargs; 167#ifdef _WIN32 168 SYSTEM_INFO sysinfo; 169 GetSystemInfo(&sysinfo); 170 switch (sysinfo.wProcessorArchitecture) { 171 case PROCESSOR_ARCHITECTURE_AMD64: return js_mkstr(js, "x86_64", 6); 172 case PROCESSOR_ARCHITECTURE_ARM64: return js_mkstr(js, "aarch64", 7); 173 case PROCESSOR_ARCHITECTURE_INTEL: return js_mkstr(js, "i686", 4); 174 case PROCESSOR_ARCHITECTURE_ARM: return js_mkstr(js, "arm", 3); 175 default: return js_mkstr(js, "unknown", 7); 176 } 177#else 178 struct utsname info; 179 if (uname(&info) == 0) { 180 return js_mkstr(js, info.machine, strlen(info.machine)); 181 } 182 return js_mkstr(js, "", 0); 183#endif 184} 185 186static ant_value_t os_hostname(ant_t *js, ant_value_t *args, int nargs) { 187 (void)args; (void)nargs; 188 char hostname[256]; 189 if (gethostname(hostname, sizeof(hostname)) == 0) { 190 return js_mkstr(js, hostname, strlen(hostname)); 191 } 192 return js_mkstr(js, "", 0); 193} 194 195static ant_value_t os_homedir(ant_t *js, ant_value_t *args, int nargs) { 196 (void)args; (void)nargs; 197#ifdef _WIN32 198 const char *userprofile = getenv("USERPROFILE"); 199 if (userprofile) { 200 return js_mkstr(js, userprofile, strlen(userprofile)); 201 } 202 const char *homedrive = getenv("HOMEDRIVE"); 203 const char *homepath = getenv("HOMEPATH"); 204 if (homedrive && homepath) { 205 static char home[MAX_PATH]; 206 snprintf(home, sizeof(home), "%s%s", homedrive, homepath); 207 return js_mkstr(js, home, strlen(home)); 208 } 209 return js_mkstr(js, "", 0); 210#else 211 const char *home = getenv("HOME"); 212 if (home) { 213 return js_mkstr(js, home, strlen(home)); 214 } 215 struct passwd *pw = getpwuid(getuid()); 216 if (pw && pw->pw_dir) { 217 return js_mkstr(js, pw->pw_dir, strlen(pw->pw_dir)); 218 } 219 return js_mkstr(js, "", 0); 220#endif 221} 222 223static ant_value_t os_tmpdir(ant_t *js, ant_value_t *args, int nargs) { 224 (void)args; (void)nargs; 225 const char *tmpdir = getenv("TMPDIR"); 226 if (!tmpdir) tmpdir = getenv("TMP"); 227 if (!tmpdir) tmpdir = getenv("TEMP"); 228 if (!tmpdir) tmpdir = "/tmp"; 229 return js_mkstr(js, tmpdir, strlen(tmpdir)); 230} 231 232static ant_value_t os_endianness(ant_t *js, ant_value_t *args, int nargs) { 233 (void)args; (void)nargs; 234 uint16_t test = 1; 235 if (*(uint8_t *)&test == 1) { 236 return js_mkstr(js, "LE", 2); 237 } 238 return js_mkstr(js, "BE", 2); 239} 240 241static ant_value_t os_uptime(ant_t *js, ant_value_t *args, int nargs) { 242 (void)args; (void)nargs; 243#ifdef _WIN32 244 return js_mknum((double)GetTickCount64() / 1000.0); 245#elif defined(__APPLE__) 246 struct timeval boottime; 247 size_t len = sizeof(boottime); 248 int mib[2] = { CTL_KERN, KERN_BOOTTIME }; 249 if (sysctl(mib, 2, &boottime, &len, NULL, 0) == 0) { 250 time_t now = time(NULL); 251 return js_mknum((double)(now - boottime.tv_sec)); 252 } 253 return js_mknum(0); 254#elif defined(__linux__) 255 struct sysinfo info; 256 if (sysinfo(&info) == 0) { 257 return js_mknum((double)info.uptime); 258 } 259 return js_mknum(0); 260#else 261 return js_mknum(0); 262#endif 263} 264 265static ant_value_t os_totalmem(ant_t *js, ant_value_t *args, int nargs) { 266 (void)args; (void)nargs; 267#ifdef _WIN32 268 MEMORYSTATUSEX memInfo; 269 memInfo.dwLength = sizeof(MEMORYSTATUSEX); 270 if (GlobalMemoryStatusEx(&memInfo)) { 271 return js_mknum((double)memInfo.ullTotalPhys); 272 } 273 return js_mknum(0); 274#elif defined(__APPLE__) 275 int64_t memsize; 276 size_t len = sizeof(memsize); 277 if (sysctlbyname("hw.memsize", &memsize, &len, NULL, 0) == 0) { 278 return js_mknum((double)memsize); 279 } 280 return js_mknum(0); 281#elif defined(__linux__) 282 struct sysinfo info; 283 if (sysinfo(&info) == 0) { 284 return js_mknum((double)info.totalram * info.mem_unit); 285 } 286 return js_mknum(0); 287#else 288 return js_mknum(0); 289#endif 290} 291 292static ant_value_t os_freemem(ant_t *js, ant_value_t *args, int nargs) { 293 (void)args; (void)nargs; 294#ifdef _WIN32 295 MEMORYSTATUSEX memInfo; 296 memInfo.dwLength = sizeof(MEMORYSTATUSEX); 297 if (GlobalMemoryStatusEx(&memInfo)) { 298 return js_mknum((double)memInfo.ullAvailPhys); 299 } 300 return js_mknum(0); 301#elif defined(__APPLE__) 302 vm_size_t page_size; 303 mach_port_t mach_port = mach_host_self(); 304 vm_statistics64_data_t vm_stats; 305 mach_msg_type_number_t count = sizeof(vm_stats) / sizeof(natural_t); 306 307 if (host_page_size(mach_port, &page_size) == KERN_SUCCESS && 308 host_statistics64(mach_port, HOST_VM_INFO64, (host_info64_t)&vm_stats, &count) == KERN_SUCCESS) { 309 return js_mknum((double)vm_stats.free_count * (double)page_size); 310 } 311 return js_mknum(0); 312#elif defined(__linux__) 313 struct sysinfo info; 314 if (sysinfo(&info) == 0) { 315 return js_mknum((double)info.freeram * info.mem_unit); 316 } 317 return js_mknum(0); 318#else 319 return js_mknum(0); 320#endif 321} 322 323static ant_value_t os_availableParallelism(ant_t *js, ant_value_t *args, int nargs) { 324 (void)args; (void)nargs; 325#ifdef _WIN32 326 SYSTEM_INFO sysinfo; 327 GetSystemInfo(&sysinfo); 328 return js_mknum((double)sysinfo.dwNumberOfProcessors); 329#elif defined(__APPLE__) 330 int count; 331 size_t size = sizeof(count); 332 if (sysctlbyname("hw.ncpu", &count, &size, NULL, 0) == 0) { 333 return js_mknum((double)count); 334 } 335 return js_mknum(1); 336#elif defined(__linux__) 337 long count = sysconf(_SC_NPROCESSORS_ONLN); 338 return js_mknum(count > 0 ? (double)count : 1); 339#else 340 return js_mknum(1); 341#endif 342} 343 344typedef struct { 345 double user, nice, sys, idle, irq; 346} cpu_times_t; 347 348static void push_cpu_entry(ant_t *js, ant_value_t arr, const char *model, double speed, cpu_times_t *times) { 349 ant_value_t cpu = js_mkobj(js); 350 js_set(js, cpu, "model", js_mkstr(js, model, strlen(model))); 351 js_set(js, cpu, "speed", js_mknum(speed)); 352 353 ant_value_t t = js_mkobj(js); 354 js_set(js, t, "user", js_mknum(times->user)); 355 js_set(js, t, "nice", js_mknum(times->nice)); 356 js_set(js, t, "sys", js_mknum(times->sys)); 357 js_set(js, t, "idle", js_mknum(times->idle)); 358 js_set(js, t, "irq", js_mknum(times->irq)); 359 js_set(js, cpu, "times", t); 360 361 js_arr_push(js, arr, cpu); 362} 363 364#ifdef __APPLE__ 365static ant_value_t os_cpus_darwin(ant_t *js) { 366 ant_value_t arr = js_mkarr(js); 367 368 natural_t ncpu; 369 processor_info_array_t cpu_info; 370 mach_msg_type_number_t info_count; 371 372 if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &ncpu, &cpu_info, &info_count) != KERN_SUCCESS) 373 return arr; 374 375 char model[256] = "Unknown"; 376 size_t len = sizeof(model); 377 sysctlbyname("machdep.cpu.brand_string", model, &len, NULL, 0); 378 379 uint64_t freq = 0; 380 len = sizeof(freq); 381 if (sysctlbyname("hw.cpufrequency", &freq, &len, NULL, 0) != 0) 382 freq = 2400000000; 383 double speed = (double)freq / 1000000.0; 384 385 processor_cpu_load_info_data_t *load = (processor_cpu_load_info_data_t *)cpu_info; 386 387 for (natural_t i = 0; i < ncpu; i++) { 388 cpu_times_t times = { 389 .user = (double)load[i].cpu_ticks[CPU_STATE_USER] * 10, 390 .nice = (double)load[i].cpu_ticks[CPU_STATE_NICE] * 10, 391 .sys = (double)load[i].cpu_ticks[CPU_STATE_SYSTEM] * 10, 392 .idle = (double)load[i].cpu_ticks[CPU_STATE_IDLE] * 10, 393 .irq = 0 394 }; 395 push_cpu_entry(js, arr, model, speed, &times); 396 } 397 398 vm_deallocate(mach_task_self(), (vm_address_t)cpu_info, info_count * sizeof(integer_t)); 399 return arr; 400} 401#endif 402 403#ifdef __linux__ 404static char *parse_colon_value(char *line) { 405 char *colon = strchr(line, ':'); 406 if (!colon) return NULL; 407 colon++; 408 while (*colon == ' ' || *colon == '\t') colon++; 409 size_t len = strlen(colon); 410 if (len > 0 && colon[len-1] == '\n') colon[len-1] = '\0'; 411 return colon; 412} 413 414static ant_value_t os_cpus_linux(ant_t *js) { 415 ant_value_t arr = js_mkarr(js); 416 char model[256] = "Unknown"; 417 double speed = 0; 418 int ncpu = 0; 419 420 FILE *fp = fopen("/proc/cpuinfo", "r"); 421 if (!fp) goto read_stat; 422 423 char line[256]; 424 while (fgets(line, sizeof(line), fp)) { 425 if (strncmp(line, "processor", 9) == 0) { ncpu++; continue; } 426 if (strncmp(line, "model name", 10) == 0) { 427 char *val = parse_colon_value(line); 428 if (val) strncpy(model, val, sizeof(model) - 1); 429 continue; 430 } 431 if (strncmp(line, "cpu MHz", 7) == 0) { 432 char *val = parse_colon_value(line); 433 if (val) speed = atof(val); 434 } 435 } 436 fclose(fp); 437 438read_stat: 439 fp = fopen("/proc/stat", "r"); 440 if (!fp) return arr; 441 442 int cpu_idx = 0; 443 while (fgets(line, sizeof(line), fp) && cpu_idx < ncpu) { 444 if (strncmp(line, "cpu", 3) != 0 || line[3] < '0' || line[3] > '9') continue; 445 446 unsigned long user, nice, sys, idle, iowait, irq, softirq; 447 if (sscanf(line, "cpu%*d %lu %lu %lu %lu %lu %lu %lu", &user, &nice, &sys, &idle, &iowait, &irq, &softirq) < 4) 448 continue; 449 450 cpu_times_t times = { 451 .user = (double)user * 10, 452 .nice = (double)nice * 10, 453 .sys = (double)sys * 10, 454 .idle = (double)idle * 10, 455 .irq = (double)(irq + softirq) * 10 456 }; 457 push_cpu_entry(js, arr, model, speed, &times); 458 cpu_idx++; 459 } 460 fclose(fp); 461 return arr; 462} 463#endif 464 465static ant_value_t os_cpus(ant_t *js, ant_value_t *args, int nargs) { 466 (void)args; (void)nargs; 467#ifdef __APPLE__ 468 return os_cpus_darwin(js); 469#elif defined(__linux__) 470 return os_cpus_linux(js); 471#else 472 return js_mkarr(js); 473#endif 474} 475 476static ant_value_t os_loadavg(ant_t *js, ant_value_t *args, int nargs) { 477 (void)args; (void)nargs; 478 ant_value_t arr = js_mkarr(js); 479 480#if defined(__APPLE__) || defined(__linux__) 481 double loadavg[3]; 482 if (getloadavg(loadavg, 3) == 3) { 483 js_arr_push(js, arr, js_mknum(loadavg[0])); 484 js_arr_push(js, arr, js_mknum(loadavg[1])); 485 js_arr_push(js, arr, js_mknum(loadavg[2])); 486 } else { 487 js_arr_push(js, arr, js_mknum(0)); 488 js_arr_push(js, arr, js_mknum(0)); 489 js_arr_push(js, arr, js_mknum(0)); 490 } 491#else 492 js_arr_push(js, arr, js_mknum(0)); 493 js_arr_push(js, arr, js_mknum(0)); 494 js_arr_push(js, arr, js_mknum(0)); 495#endif 496 497 return arr; 498} 499 500#ifdef _WIN32 501 502static ant_value_t os_networkInterfaces(ant_t *js, ant_value_t *args, int nargs) { 503 (void)args; (void)nargs; 504 ant_value_t result = js_mkobj(js); 505 506 ULONG bufLen = 15000; 507 PIP_ADAPTER_ADDRESSES pAddresses = NULL; 508 PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; 509 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; 510 511 pAddresses = (IP_ADAPTER_ADDRESSES *)malloc(bufLen); 512 if (!pAddresses) return result; 513 514 ULONG ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &bufLen); 515 if (ret == ERROR_BUFFER_OVERFLOW) { 516 free(pAddresses); 517 pAddresses = (IP_ADAPTER_ADDRESSES *)malloc(bufLen); 518 if (!pAddresses) return result; 519 ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &bufLen); 520 } 521 522 if (ret != NO_ERROR) { 523 free(pAddresses); 524 return result; 525 } 526 527 for (pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) { 528 ant_value_t iface_arr = js_get(js, result, pCurrAddresses->AdapterName); 529 if (!is_special_object(iface_arr)) { 530 iface_arr = js_mkarr(js); 531 js_set(js, result, pCurrAddresses->AdapterName, iface_arr); 532 } 533 534 char mac_str[18] = "00:00:00:00:00:00"; 535 if (pCurrAddresses->PhysicalAddressLength == 6) { 536 snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", 537 pCurrAddresses->PhysicalAddress[0], pCurrAddresses->PhysicalAddress[1], 538 pCurrAddresses->PhysicalAddress[2], pCurrAddresses->PhysicalAddress[3], 539 pCurrAddresses->PhysicalAddress[4], pCurrAddresses->PhysicalAddress[5]); 540 } 541 542 bool internal = (pCurrAddresses->IfType == IF_TYPE_SOFTWARE_LOOPBACK); 543 544 for (pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { 545 ant_value_t entry = js_mkobj(js); 546 js_set(js, entry, "mac", js_mkstr(js, mac_str, strlen(mac_str))); 547 js_set(js, entry, "internal", js_bool(internal)); 548 549 char addr_str[INET6_ADDRSTRLEN] = ""; 550 struct sockaddr *sa = pUnicast->Address.lpSockaddr; 551 552 if (sa->sa_family == AF_INET) { 553 struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; 554 inet_ntop(AF_INET, &sa4->sin_addr, addr_str, sizeof(addr_str)); 555 js_set(js, entry, "address", js_mkstr(js, addr_str, strlen(addr_str))); 556 js_set(js, entry, "family", js_mkstr(js, "IPv4", 4)); 557 js_set(js, entry, "netmask", js_mkstr(js, "", 0)); 558 js_set(js, entry, "cidr", js_mkstr(js, addr_str, strlen(addr_str))); 559 } else if (sa->sa_family == AF_INET6) { 560 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 561 inet_ntop(AF_INET6, &sa6->sin6_addr, addr_str, sizeof(addr_str)); 562 js_set(js, entry, "address", js_mkstr(js, addr_str, strlen(addr_str))); 563 js_set(js, entry, "family", js_mkstr(js, "IPv6", 4)); 564 js_set(js, entry, "netmask", js_mkstr(js, "", 0)); 565 js_set(js, entry, "scopeid", js_mknum((double)sa6->sin6_scope_id)); 566 js_set(js, entry, "cidr", js_mkstr(js, addr_str, strlen(addr_str))); 567 } else { 568 continue; 569 } 570 571 js_arr_push(js, iface_arr, entry); 572 } 573 } 574 575 free(pAddresses); 576 return result; 577} 578 579static ant_value_t os_userInfo(ant_t *js, ant_value_t *args, int nargs) { 580 (void)args; (void)nargs; 581 ant_value_t info = js_mkobj(js); 582 583 js_set(js, info, "uid", js_mknum(-1)); 584 js_set(js, info, "gid", js_mknum(-1)); 585 586 char username[UNLEN + 1]; 587 DWORD username_len = sizeof(username); 588 if (GetUserNameA(username, &username_len)) { 589 js_set(js, info, "username", js_mkstr(js, username, strlen(username))); 590 } else { 591 js_set(js, info, "username", js_mkstr(js, "", 0)); 592 } 593 594 const char *userprofile = getenv("USERPROFILE"); 595 if (userprofile) { 596 js_set(js, info, "homedir", js_mkstr(js, userprofile, strlen(userprofile))); 597 } else { 598 js_set(js, info, "homedir", js_mkstr(js, "", 0)); 599 } 600 601 js_set(js, info, "shell", js_mknull()); 602 603 return info; 604} 605 606static ant_value_t os_getPriority(ant_t *js, ant_value_t *args, int nargs) { 607 (void)args; (void)nargs; 608 return js_mknum(0); 609} 610 611static ant_value_t os_setPriority(ant_t *js, ant_value_t *args, int nargs) { 612 (void)args; (void)nargs; 613 return js_mkundef(); 614} 615 616#else 617 618static void format_mac_address(char *buf, size_t buflen, unsigned char *addr) { 619 snprintf(buf, buflen, "%02x:%02x:%02x:%02x:%02x:%02x", 620 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 621} 622 623static int calc_prefix_len(struct sockaddr *netmask, int family) { 624 int prefix = 0; 625 if (family == AF_INET) { 626 uint32_t mask = ntohl(((struct sockaddr_in *)netmask)->sin_addr.s_addr); 627 while (mask & 0x80000000) { prefix++; mask <<= 1; } 628 } else if (family == AF_INET6) { 629 uint8_t *bytes = ((struct sockaddr_in6 *)netmask)->sin6_addr.s6_addr; 630 for (int i = 0; i < 16; i++) { 631 uint8_t b = bytes[i]; 632 while (b & 0x80) { prefix++; b <<= 1; } 633 if (b) break; 634 } 635 } 636 return prefix; 637} 638 639static void add_iface_entry(ant_t *js, ant_value_t iface_arr, struct ifaddrs *ifa, int family) { 640 char addr_str[INET6_ADDRSTRLEN] = ""; 641 char netmask_str[INET6_ADDRSTRLEN] = ""; 642 char cidr[128]; 643 bool internal = (ifa->ifa_flags & IFF_LOOPBACK) != 0; 644 645 ant_value_t entry = js_mkobj(js); 646 js_set(js, entry, "mac", js_mkstr(js, "00:00:00:00:00:00", 17)); 647 js_set(js, entry, "internal", js_bool(internal)); 648 649 if (family == AF_INET) { 650 struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr; 651 inet_ntop(AF_INET, &sa->sin_addr, addr_str, sizeof(addr_str)); 652 if (ifa->ifa_netmask) 653 inet_ntop(AF_INET, &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr, netmask_str, sizeof(netmask_str)); 654 655 int prefix = ifa->ifa_netmask ? calc_prefix_len(ifa->ifa_netmask, AF_INET) : 0; 656 snprintf(cidr, sizeof(cidr), "%s/%d", addr_str, prefix); 657 658 js_set(js, entry, "address", js_mkstr(js, addr_str, strlen(addr_str))); 659 js_set(js, entry, "netmask", js_mkstr(js, netmask_str, strlen(netmask_str))); 660 js_set(js, entry, "family", js_mkstr(js, "IPv4", 4)); 661 js_set(js, entry, "cidr", js_mkstr(js, cidr, strlen(cidr))); 662 goto push; 663 } 664 665 if (family == AF_INET6) { 666 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ifa->ifa_addr; 667 inet_ntop(AF_INET6, &sa6->sin6_addr, addr_str, sizeof(addr_str)); 668 if (ifa->ifa_netmask) 669 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr, netmask_str, sizeof(netmask_str)); 670 671 int prefix = ifa->ifa_netmask ? calc_prefix_len(ifa->ifa_netmask, AF_INET6) : 0; 672 snprintf(cidr, sizeof(cidr), "%s/%d", addr_str, prefix); 673 674 js_set(js, entry, "address", js_mkstr(js, addr_str, strlen(addr_str))); 675 js_set(js, entry, "netmask", js_mkstr(js, netmask_str, strlen(netmask_str))); 676 js_set(js, entry, "family", js_mkstr(js, "IPv6", 4)); 677 js_set(js, entry, "scopeid", js_mknum((double)sa6->sin6_scope_id)); 678 js_set(js, entry, "cidr", js_mkstr(js, cidr, strlen(cidr))); 679 goto push; 680 } 681 682 return; 683push: 684 js_arr_push(js, iface_arr, entry); 685} 686 687static unsigned char *get_mac_bytes(struct ifaddrs *ifa) { 688#ifdef __APPLE__ 689 if (ifa->ifa_addr->sa_family != AF_LINK) return NULL; 690 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; 691 return (sdl->sdl_alen == 6) ? (unsigned char *)LLADDR(sdl) : NULL; 692#elif defined(__linux__) 693 if (ifa->ifa_addr->sa_family != AF_PACKET) return NULL; 694 struct sockaddr_ll *sll = (struct sockaddr_ll *)ifa->ifa_addr; 695 return (sll->sll_halen == 6) ? sll->sll_addr : NULL; 696#else 697 (void)ifa; 698 return NULL; 699#endif 700} 701 702static void apply_mac_to_iface(ant_t *js, ant_value_t result, const char *name, unsigned char *mac_bytes) { 703 char mac_str[18]; 704 format_mac_address(mac_str, sizeof(mac_str), mac_bytes); 705 706 ant_value_t iface_arr = js_get(js, result, name); 707 if (!is_special_object(iface_arr)) return; 708 709 ant_value_t len_val = js_get(js, iface_arr, "length"); 710 int len = (vtype(len_val) == T_NUM) ? (int)js_getnum(len_val) : 0; 711 712 for (int i = 0; i < len; i++) { 713 char idx[16]; 714 snprintf(idx, sizeof(idx), "%d", i); 715 ant_value_t entry = js_get(js, iface_arr, idx); 716 if (is_special_object(entry)) { 717 js_set(js, entry, "mac", js_mkstr(js, mac_str, strlen(mac_str))); 718 } 719 } 720} 721 722static ant_value_t os_networkInterfaces(ant_t *js, ant_value_t *args, int nargs) { 723 (void)args; (void)nargs; 724 ant_value_t result = js_mkobj(js); 725 726 struct ifaddrs *addrs, *ifa; 727 if (getifaddrs(&addrs) != 0) return result; 728 729 for (ifa = addrs; ifa; ifa = ifa->ifa_next) { 730 if (!ifa->ifa_addr) continue; 731 732 int family = ifa->ifa_addr->sa_family; 733 if (family != AF_INET && family != AF_INET6) continue; 734 735 ant_value_t iface_arr = js_get(js, result, ifa->ifa_name); 736 if (!is_special_object(iface_arr)) { 737 iface_arr = js_mkarr(js); 738 js_set(js, result, ifa->ifa_name, iface_arr); 739 } 740 741 add_iface_entry(js, iface_arr, ifa, family); 742 } 743 744 for (ifa = addrs; ifa; ifa = ifa->ifa_next) { 745 if (!ifa->ifa_addr) continue; 746 747 unsigned char *mac_bytes = get_mac_bytes(ifa); 748 if (mac_bytes) 749 apply_mac_to_iface(js, result, ifa->ifa_name, mac_bytes); 750 } 751 752 freeifaddrs(addrs); 753 return result; 754} 755 756static ant_value_t os_userInfo(ant_t *js, ant_value_t *args, int nargs) { 757 (void)args; (void)nargs; 758 ant_value_t info = js_mkobj(js); 759 760 uid_t uid = getuid(); 761 gid_t gid = getgid(); 762 struct passwd *pw = getpwuid(uid); 763 764 js_set(js, info, "uid", js_mknum((double)uid)); 765 js_set(js, info, "gid", js_mknum((double)gid)); 766 767 if (pw) { 768 if (pw->pw_name) js_set(js, info, "username", js_mkstr(js, pw->pw_name, strlen(pw->pw_name))); 769 else js_set(js, info, "username", js_mkstr(js, "", 0)); 770 771 if (pw->pw_dir) js_set(js, info, "homedir", js_mkstr(js, pw->pw_dir, strlen(pw->pw_dir))); 772 else js_set(js, info, "homedir", js_mkstr(js, "", 0)); 773 774 if (pw->pw_shell) js_set(js, info, "shell", js_mkstr(js, pw->pw_shell, strlen(pw->pw_shell))); 775 else js_set(js, info, "shell", js_mknull()); 776 } else { 777 js_set(js, info, "username", js_mkstr(js, "", 0)); 778 js_set(js, info, "homedir", js_mkstr(js, "", 0)); 779 js_set(js, info, "shell", js_mknull()); 780 } 781 782 return info; 783} 784 785static ant_value_t os_getPriority(ant_t *js, ant_value_t *args, int nargs) { 786 int pid = 0; 787 if (nargs > 0 && vtype(args[0]) == T_NUM) { 788 pid = (int)js_getnum(args[0]); 789 } 790 791 errno = 0; 792 int priority = getpriority(PRIO_PROCESS, pid); 793 if (errno != 0) { 794 return js_mkerr(js, "Failed to get priority: %s", strerror(errno)); 795 } 796 return js_mknum((double)priority); 797} 798 799static ant_value_t os_setPriority(ant_t *js, ant_value_t *args, int nargs) { 800 int pid = 0; 801 int priority = 0; 802 803 if (nargs == 1) { 804 if (vtype(args[0]) != T_NUM) { 805 return js_mkerr_typed(js, JS_ERR_TYPE, "priority must be a number"); 806 } 807 priority = (int)js_getnum(args[0]); 808 } else if (nargs >= 2) { 809 if (vtype(args[0]) != T_NUM || vtype(args[1]) != T_NUM) { 810 return js_mkerr_typed(js, JS_ERR_TYPE, "pid and priority must be numbers"); 811 } 812 pid = (int)js_getnum(args[0]); 813 priority = (int)js_getnum(args[1]); 814 } else { 815 return js_mkerr_typed(js, JS_ERR_TYPE, "setPriority requires at least 1 argument"); 816 } 817 818 if (setpriority(PRIO_PROCESS, pid, priority) != 0) { 819 return js_mkerr(js, "Failed to set priority: %s", strerror(errno)); 820 } 821 return js_mkundef(); 822} 823 824#endif 825 826static void add_signal_constants(ant_t *js, ant_value_t signals) { 827#ifdef SIGHUP 828 js_set(js, signals, "SIGHUP", js_mknum(SIGHUP)); 829#endif 830#ifdef SIGINT 831 js_set(js, signals, "SIGINT", js_mknum(SIGINT)); 832#endif 833#ifdef SIGQUIT 834 js_set(js, signals, "SIGQUIT", js_mknum(SIGQUIT)); 835#endif 836#ifdef SIGILL 837 js_set(js, signals, "SIGILL", js_mknum(SIGILL)); 838#endif 839#ifdef SIGTRAP 840 js_set(js, signals, "SIGTRAP", js_mknum(SIGTRAP)); 841#endif 842#ifdef SIGABRT 843 js_set(js, signals, "SIGABRT", js_mknum(SIGABRT)); 844#endif 845#ifdef SIGIOT 846 js_set(js, signals, "SIGIOT", js_mknum(SIGIOT)); 847#endif 848#ifdef SIGBUS 849 js_set(js, signals, "SIGBUS", js_mknum(SIGBUS)); 850#endif 851#ifdef SIGFPE 852 js_set(js, signals, "SIGFPE", js_mknum(SIGFPE)); 853#endif 854#ifdef SIGKILL 855 js_set(js, signals, "SIGKILL", js_mknum(SIGKILL)); 856#endif 857#ifdef SIGUSR1 858 js_set(js, signals, "SIGUSR1", js_mknum(SIGUSR1)); 859#endif 860#ifdef SIGUSR2 861 js_set(js, signals, "SIGUSR2", js_mknum(SIGUSR2)); 862#endif 863#ifdef SIGSEGV 864 js_set(js, signals, "SIGSEGV", js_mknum(SIGSEGV)); 865#endif 866#ifdef SIGPIPE 867 js_set(js, signals, "SIGPIPE", js_mknum(SIGPIPE)); 868#endif 869#ifdef SIGALRM 870 js_set(js, signals, "SIGALRM", js_mknum(SIGALRM)); 871#endif 872#ifdef SIGTERM 873 js_set(js, signals, "SIGTERM", js_mknum(SIGTERM)); 874#endif 875#ifdef SIGCHLD 876 js_set(js, signals, "SIGCHLD", js_mknum(SIGCHLD)); 877#endif 878#ifdef SIGCONT 879 js_set(js, signals, "SIGCONT", js_mknum(SIGCONT)); 880#endif 881#ifdef SIGSTOP 882 js_set(js, signals, "SIGSTOP", js_mknum(SIGSTOP)); 883#endif 884#ifdef SIGTSTP 885 js_set(js, signals, "SIGTSTP", js_mknum(SIGTSTP)); 886#endif 887#ifdef SIGTTIN 888 js_set(js, signals, "SIGTTIN", js_mknum(SIGTTIN)); 889#endif 890#ifdef SIGTTOU 891 js_set(js, signals, "SIGTTOU", js_mknum(SIGTTOU)); 892#endif 893#ifdef SIGURG 894 js_set(js, signals, "SIGURG", js_mknum(SIGURG)); 895#endif 896#ifdef SIGXCPU 897 js_set(js, signals, "SIGXCPU", js_mknum(SIGXCPU)); 898#endif 899#ifdef SIGXFSZ 900 js_set(js, signals, "SIGXFSZ", js_mknum(SIGXFSZ)); 901#endif 902#ifdef SIGVTALRM 903 js_set(js, signals, "SIGVTALRM", js_mknum(SIGVTALRM)); 904#endif 905#ifdef SIGPROF 906 js_set(js, signals, "SIGPROF", js_mknum(SIGPROF)); 907#endif 908#ifdef SIGWINCH 909 js_set(js, signals, "SIGWINCH", js_mknum(SIGWINCH)); 910#endif 911#ifdef SIGIO 912 js_set(js, signals, "SIGIO", js_mknum(SIGIO)); 913#endif 914#ifdef SIGSYS 915 js_set(js, signals, "SIGSYS", js_mknum(SIGSYS)); 916#endif 917} 918 919static void add_errno_constants(ant_t *js, ant_value_t errn) { 920 js_set(js, errn, "E2BIG", js_mknum(E2BIG)); 921 js_set(js, errn, "EACCES", js_mknum(EACCES)); 922 js_set(js, errn, "EADDRINUSE", js_mknum(EADDRINUSE)); 923 js_set(js, errn, "EADDRNOTAVAIL", js_mknum(EADDRNOTAVAIL)); 924 js_set(js, errn, "EAFNOSUPPORT", js_mknum(EAFNOSUPPORT)); 925 js_set(js, errn, "EAGAIN", js_mknum(EAGAIN)); 926 js_set(js, errn, "EALREADY", js_mknum(EALREADY)); 927 js_set(js, errn, "EBADF", js_mknum(EBADF)); 928 js_set(js, errn, "EBUSY", js_mknum(EBUSY)); 929 js_set(js, errn, "ECANCELED", js_mknum(ECANCELED)); 930 js_set(js, errn, "ECHILD", js_mknum(ECHILD)); 931 js_set(js, errn, "ECONNABORTED", js_mknum(ECONNABORTED)); 932 js_set(js, errn, "ECONNREFUSED", js_mknum(ECONNREFUSED)); 933 js_set(js, errn, "ECONNRESET", js_mknum(ECONNRESET)); 934 js_set(js, errn, "EDEADLK", js_mknum(EDEADLK)); 935 js_set(js, errn, "EDESTADDRREQ", js_mknum(EDESTADDRREQ)); 936 js_set(js, errn, "EDOM", js_mknum(EDOM)); 937 js_set(js, errn, "EEXIST", js_mknum(EEXIST)); 938 js_set(js, errn, "EFAULT", js_mknum(EFAULT)); 939 js_set(js, errn, "EFBIG", js_mknum(EFBIG)); 940 js_set(js, errn, "EHOSTUNREACH", js_mknum(EHOSTUNREACH)); 941 js_set(js, errn, "EINPROGRESS", js_mknum(EINPROGRESS)); 942 js_set(js, errn, "EINTR", js_mknum(EINTR)); 943 js_set(js, errn, "EINVAL", js_mknum(EINVAL)); 944 js_set(js, errn, "EIO", js_mknum(EIO)); 945 js_set(js, errn, "EISCONN", js_mknum(EISCONN)); 946 js_set(js, errn, "EISDIR", js_mknum(EISDIR)); 947 js_set(js, errn, "ELOOP", js_mknum(ELOOP)); 948 js_set(js, errn, "EMFILE", js_mknum(EMFILE)); 949 js_set(js, errn, "EMLINK", js_mknum(EMLINK)); 950 js_set(js, errn, "EMSGSIZE", js_mknum(EMSGSIZE)); 951 js_set(js, errn, "ENAMETOOLONG", js_mknum(ENAMETOOLONG)); 952 js_set(js, errn, "ENETDOWN", js_mknum(ENETDOWN)); 953 js_set(js, errn, "ENETRESET", js_mknum(ENETRESET)); 954 js_set(js, errn, "ENETUNREACH", js_mknum(ENETUNREACH)); 955 js_set(js, errn, "ENFILE", js_mknum(ENFILE)); 956 js_set(js, errn, "ENOBUFS", js_mknum(ENOBUFS)); 957 js_set(js, errn, "ENODEV", js_mknum(ENODEV)); 958 js_set(js, errn, "ENOENT", js_mknum(ENOENT)); 959 js_set(js, errn, "ENOEXEC", js_mknum(ENOEXEC)); 960 js_set(js, errn, "ENOLCK", js_mknum(ENOLCK)); 961 js_set(js, errn, "ENOMEM", js_mknum(ENOMEM)); 962 js_set(js, errn, "ENOPROTOOPT", js_mknum(ENOPROTOOPT)); 963 js_set(js, errn, "ENOSPC", js_mknum(ENOSPC)); 964 js_set(js, errn, "ENOSYS", js_mknum(ENOSYS)); 965 js_set(js, errn, "ENOTCONN", js_mknum(ENOTCONN)); 966 js_set(js, errn, "ENOTDIR", js_mknum(ENOTDIR)); 967 js_set(js, errn, "ENOTEMPTY", js_mknum(ENOTEMPTY)); 968 js_set(js, errn, "ENOTSOCK", js_mknum(ENOTSOCK)); 969 js_set(js, errn, "ENOTSUP", js_mknum(ENOTSUP)); 970 js_set(js, errn, "ENOTTY", js_mknum(ENOTTY)); 971 js_set(js, errn, "ENXIO", js_mknum(ENXIO)); 972 js_set(js, errn, "EOPNOTSUPP", js_mknum(EOPNOTSUPP)); 973 js_set(js, errn, "EOVERFLOW", js_mknum(EOVERFLOW)); 974 js_set(js, errn, "EPERM", js_mknum(EPERM)); 975 js_set(js, errn, "EPIPE", js_mknum(EPIPE)); 976 js_set(js, errn, "EPROTONOSUPPORT", js_mknum(EPROTONOSUPPORT)); 977 js_set(js, errn, "EPROTOTYPE", js_mknum(EPROTOTYPE)); 978 js_set(js, errn, "ERANGE", js_mknum(ERANGE)); 979 js_set(js, errn, "EROFS", js_mknum(EROFS)); 980 js_set(js, errn, "ESPIPE", js_mknum(ESPIPE)); 981 js_set(js, errn, "ESRCH", js_mknum(ESRCH)); 982 js_set(js, errn, "ETIMEDOUT", js_mknum(ETIMEDOUT)); 983 js_set(js, errn, "ETXTBSY", js_mknum(ETXTBSY)); 984 js_set(js, errn, "EWOULDBLOCK", js_mknum(EWOULDBLOCK)); 985 js_set(js, errn, "EXDEV", js_mknum(EXDEV)); 986} 987 988static void add_priority_constants(ant_t *js, ant_value_t priority) { 989 js_set(js, priority, "PRIORITY_LOW", js_mknum(19)); 990 js_set(js, priority, "PRIORITY_BELOW_NORMAL", js_mknum(10)); 991 js_set(js, priority, "PRIORITY_NORMAL", js_mknum(0)); 992 js_set(js, priority, "PRIORITY_ABOVE_NORMAL", js_mknum(-7)); 993 js_set(js, priority, "PRIORITY_HIGH", js_mknum(-14)); 994 js_set(js, priority, "PRIORITY_HIGHEST", js_mknum(-20)); 995} 996 997static void add_dlopen_constants(ant_t *js, ant_value_t dlopen_obj) { 998#ifdef RTLD_LAZY 999 js_set(js, dlopen_obj, "RTLD_LAZY", js_mknum(RTLD_LAZY)); 1000#endif 1001#ifdef RTLD_NOW 1002 js_set(js, dlopen_obj, "RTLD_NOW", js_mknum(RTLD_NOW)); 1003#endif 1004#ifdef RTLD_GLOBAL 1005 js_set(js, dlopen_obj, "RTLD_GLOBAL", js_mknum(RTLD_GLOBAL)); 1006#endif 1007#ifdef RTLD_LOCAL 1008 js_set(js, dlopen_obj, "RTLD_LOCAL", js_mknum(RTLD_LOCAL)); 1009#endif 1010#ifdef RTLD_DEEPBIND 1011 js_set(js, dlopen_obj, "RTLD_DEEPBIND", js_mknum(RTLD_DEEPBIND)); 1012#endif 1013} 1014 1015ant_value_t os_library(ant_t *js) { 1016 ant_value_t lib = js_mkobj(js); 1017 1018 js_set(js, lib, "EOL", js_mkstr(js, OS_EOL, strlen(OS_EOL))); 1019 js_set(js, lib, "devNull", js_mkstr(js, OS_DEVNULL, strlen(OS_DEVNULL))); 1020 1021 js_set(js, lib, "arch", js_mkfun(os_arch)); 1022 js_set(js, lib, "platform", js_mkfun(os_platform)); 1023 js_set(js, lib, "type", js_mkfun(os_type)); 1024 js_set(js, lib, "release", js_mkfun(os_release)); 1025 js_set(js, lib, "version", js_mkfun(os_version)); 1026 js_set(js, lib, "machine", js_mkfun(os_machine)); 1027 js_set(js, lib, "hostname", js_mkfun(os_hostname)); 1028 js_set(js, lib, "homedir", js_mkfun(os_homedir)); 1029 js_set(js, lib, "tmpdir", js_mkfun(os_tmpdir)); 1030 js_set(js, lib, "endianness", js_mkfun(os_endianness)); 1031 js_set(js, lib, "uptime", js_mkfun(os_uptime)); 1032 js_set(js, lib, "totalmem", js_mkfun(os_totalmem)); 1033 js_set(js, lib, "freemem", js_mkfun(os_freemem)); 1034 js_set(js, lib, "availableParallelism", js_mkfun(os_availableParallelism)); 1035 js_set(js, lib, "cpus", js_mkfun(os_cpus)); 1036 js_set(js, lib, "loadavg", js_mkfun(os_loadavg)); 1037 js_set(js, lib, "networkInterfaces", js_mkfun(os_networkInterfaces)); 1038 js_set(js, lib, "userInfo", js_mkfun(os_userInfo)); 1039 js_set(js, lib, "getPriority", js_mkfun(os_getPriority)); 1040 js_set(js, lib, "setPriority", js_mkfun(os_setPriority)); 1041 1042 ant_value_t constants = js_mkobj(js); 1043 ant_value_t signals = js_mkobj(js); 1044 ant_value_t errn = js_mkobj(js); 1045 ant_value_t priority = js_mkobj(js); 1046 ant_value_t dlopen_obj = js_mkobj(js); 1047 1048 add_signal_constants(js, signals); 1049 add_errno_constants(js, errn); 1050 add_priority_constants(js, priority); 1051 add_dlopen_constants(js, dlopen_obj); 1052 1053 js_set(js, constants, "signals", signals); 1054 js_set(js, constants, "errno", errn); 1055 js_set(js, constants, "priority", priority); 1056 js_set(js, constants, "dlopen", dlopen_obj); 1057 js_set(js, constants, "UV_UDP_REUSEADDR", js_mknum(4)); 1058 js_set(js, lib, "constants", constants); 1059 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "os", 2)); 1060 1061 return lib; 1062}