MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
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, ×);
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, ×);
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}