1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18 * IN THE SOFTWARE.
19 */
20
21 #include "uv.h"
22 #include "internal.h"
23
24 #include <assert.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <kvm.h>
29 #include <paths.h>
30 #include <ifaddrs.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <stdlib.h>
34 #include <fcntl.h>
35
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <sys/resource.h>
39 #include <sys/types.h>
40 #include <sys/sysctl.h>
41
42 #ifdef __NetBSD__
43 #include <uvm/uvm_extern.h>
44 #endif
45
46 #include <unistd.h>
47 #include <time.h>
48
49 #undef NANOSEC
50 #define NANOSEC ((uint64_t) 1e9)
51
52 static char *process_title;
53
54
uv__platform_loop_init(uv_loop_t * loop,int default_loop)55 int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
56 return uv__kqueue_init(loop);
57 }
58
59
uv__platform_loop_delete(uv_loop_t * loop)60 void uv__platform_loop_delete(uv_loop_t* loop) {
61 }
62
63
uv__hrtime(uv_clocktype_t type)64 uint64_t uv__hrtime(uv_clocktype_t type) {
65 struct timespec ts;
66 clock_gettime(CLOCK_MONOTONIC, &ts);
67 return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
68 }
69
70
uv_loadavg(double avg[3])71 void uv_loadavg(double avg[3]) {
72 struct loadavg info;
73 size_t size = sizeof(info);
74 int which[] = {CTL_VM, VM_LOADAVG};
75
76 if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
77
78 avg[0] = (double) info.ldavg[0] / info.fscale;
79 avg[1] = (double) info.ldavg[1] / info.fscale;
80 avg[2] = (double) info.ldavg[2] / info.fscale;
81 }
82
83
uv_exepath(char * buffer,size_t * size)84 int uv_exepath(char* buffer, size_t* size) {
85 int mib[4];
86 size_t cb;
87 pid_t mypid;
88
89 if (buffer == NULL || size == NULL)
90 return -EINVAL;
91
92 mypid = getpid();
93 mib[0] = CTL_KERN;
94 mib[1] = KERN_PROC_ARGS;
95 mib[2] = mypid;
96 mib[3] = KERN_PROC_ARGV;
97
98 cb = *size;
99 if (sysctl(mib, 4, buffer, &cb, NULL, 0))
100 return -errno;
101 *size = strlen(buffer);
102
103 return 0;
104 }
105
106
uv_get_free_memory(void)107 uint64_t uv_get_free_memory(void) {
108 struct uvmexp info;
109 size_t size = sizeof(info);
110 int which[] = {CTL_VM, VM_UVMEXP};
111
112 if (sysctl(which, 2, &info, &size, NULL, 0))
113 return -errno;
114
115 return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
116 }
117
118
uv_get_total_memory(void)119 uint64_t uv_get_total_memory(void) {
120 #if defined(HW_PHYSMEM64)
121 uint64_t info;
122 int which[] = {CTL_HW, HW_PHYSMEM64};
123 #else
124 unsigned int info;
125 int which[] = {CTL_HW, HW_PHYSMEM};
126 #endif
127 size_t size = sizeof(info);
128
129 if (sysctl(which, 2, &info, &size, NULL, 0))
130 return -errno;
131
132 return (uint64_t) info;
133 }
134
135
uv_setup_args(int argc,char ** argv)136 char** uv_setup_args(int argc, char** argv) {
137 process_title = argc ? strdup(argv[0]) : NULL;
138 return argv;
139 }
140
141
uv_set_process_title(const char * title)142 int uv_set_process_title(const char* title) {
143 if (process_title) free(process_title);
144
145 process_title = strdup(title);
146 setproctitle("%s", title);
147
148 return 0;
149 }
150
151
uv_get_process_title(char * buffer,size_t size)152 int uv_get_process_title(char* buffer, size_t size) {
153 if (process_title) {
154 strncpy(buffer, process_title, size);
155 } else {
156 if (size > 0) {
157 buffer[0] = '\0';
158 }
159 }
160
161 return 0;
162 }
163
164
uv_resident_set_memory(size_t * rss)165 int uv_resident_set_memory(size_t* rss) {
166 kvm_t *kd = NULL;
167 struct kinfo_proc2 *kinfo = NULL;
168 pid_t pid;
169 int nprocs;
170 int max_size = sizeof(struct kinfo_proc2);
171 int page_size;
172
173 page_size = getpagesize();
174 pid = getpid();
175
176 kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
177
178 if (kd == NULL) goto error;
179
180 kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
181 if (kinfo == NULL) goto error;
182
183 *rss = kinfo->p_vm_rssize * page_size;
184
185 kvm_close(kd);
186
187 return 0;
188
189 error:
190 if (kd) kvm_close(kd);
191 return -EPERM;
192 }
193
194
uv_uptime(double * uptime)195 int uv_uptime(double* uptime) {
196 time_t now;
197 struct timeval info;
198 size_t size = sizeof(info);
199 static int which[] = {CTL_KERN, KERN_BOOTTIME};
200
201 if (sysctl(which, 2, &info, &size, NULL, 0))
202 return -errno;
203
204 now = time(NULL);
205
206 *uptime = (double)(now - info.tv_sec);
207 return 0;
208 }
209
210
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)211 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
212 unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
213 unsigned int multiplier = ((uint64_t)1000L / ticks);
214 unsigned int cur = 0;
215 uv_cpu_info_t* cpu_info;
216 u_int64_t* cp_times;
217 char model[512];
218 u_int64_t cpuspeed;
219 int numcpus;
220 size_t size;
221 int i;
222
223 size = sizeof(model);
224 if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
225 sysctlbyname("hw.model", &model, &size, NULL, 0)) {
226 return -errno;
227 }
228
229 size = sizeof(numcpus);
230 if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
231 return -errno;
232 *count = numcpus;
233
234 /* Only i386 and amd64 have machdep.tsc_freq */
235 size = sizeof(cpuspeed);
236 if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
237 cpuspeed = 0;
238
239 size = numcpus * CPUSTATES * sizeof(*cp_times);
240 cp_times = malloc(size);
241 if (cp_times == NULL)
242 return -ENOMEM;
243
244 if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
245 return -errno;
246
247 *cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
248 if (!(*cpu_infos)) {
249 free(cp_times);
250 free(*cpu_infos);
251 return -ENOMEM;
252 }
253
254 for (i = 0; i < numcpus; i++) {
255 cpu_info = &(*cpu_infos)[i];
256 cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
257 cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
258 cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
259 cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
260 cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
261 cpu_info->model = strdup(model);
262 cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
263 cur += CPUSTATES;
264 }
265 free(cp_times);
266 return 0;
267 }
268
269
uv_free_cpu_info(uv_cpu_info_t * cpu_infos,int count)270 void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
271 int i;
272
273 for (i = 0; i < count; i++) {
274 free(cpu_infos[i].model);
275 }
276
277 free(cpu_infos);
278 }
279
280
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)281 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
282 struct ifaddrs *addrs, *ent;
283 uv_interface_address_t* address;
284 int i;
285 struct sockaddr_dl *sa_addr;
286
287 if (getifaddrs(&addrs))
288 return -errno;
289
290 *count = 0;
291
292 /* Count the number of interfaces */
293 for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
294 if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
295 (ent->ifa_addr == NULL) ||
296 (ent->ifa_addr->sa_family != PF_INET)) {
297 continue;
298 }
299 (*count)++;
300 }
301
302 *addresses = malloc(*count * sizeof(**addresses));
303
304 if (!(*addresses))
305 return -ENOMEM;
306
307 address = *addresses;
308
309 for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
310 if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
311 continue;
312
313 if (ent->ifa_addr == NULL)
314 continue;
315
316 if (ent->ifa_addr->sa_family != PF_INET)
317 continue;
318
319 address->name = strdup(ent->ifa_name);
320
321 if (ent->ifa_addr->sa_family == AF_INET6) {
322 address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
323 } else {
324 address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
325 }
326
327 if (ent->ifa_netmask->sa_family == AF_INET6) {
328 address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
329 } else {
330 address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
331 }
332
333 address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
334
335 address++;
336 }
337
338 /* Fill in physical addresses for each interface */
339 for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
340 if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
341 (ent->ifa_addr == NULL) ||
342 (ent->ifa_addr->sa_family != AF_LINK)) {
343 continue;
344 }
345
346 address = *addresses;
347
348 for (i = 0; i < (*count); i++) {
349 if (strcmp(address->name, ent->ifa_name) == 0) {
350 sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
351 memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
352 }
353 address++;
354 }
355 }
356
357 freeifaddrs(addrs);
358
359 return 0;
360 }
361
362
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)363 void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
364 int i;
365
366 for (i = 0; i < count; i++) {
367 free(addresses[i].name);
368 }
369
370 free(addresses);
371 }
372