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