• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdio.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 
31 #ifndef SUNOS_NO_IFADDRS
32 # include <ifaddrs.h>
33 #endif
34 #include <net/if.h>
35 #include <net/if_dl.h>
36 #include <net/if_arp.h>
37 #include <sys/sockio.h>
38 
39 #include <sys/loadavg.h>
40 #include <sys/time.h>
41 #include <unistd.h>
42 #include <kstat.h>
43 #include <fcntl.h>
44 
45 #include <sys/port.h>
46 #include <port.h>
47 
48 #define PORT_FIRED 0x69
49 #define PORT_UNUSED 0x0
50 #define PORT_LOADED 0x99
51 #define PORT_DELETED -1
52 
53 #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
54 #define PROCFS_FILE_OFFSET_BITS_HACK 1
55 #undef _FILE_OFFSET_BITS
56 #else
57 #define PROCFS_FILE_OFFSET_BITS_HACK 0
58 #endif
59 
60 #include <procfs.h>
61 
62 #if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
63 #define _FILE_OFFSET_BITS 64
64 #endif
65 
66 
uv__platform_loop_init(uv_loop_t * loop)67 int uv__platform_loop_init(uv_loop_t* loop) {
68   int err;
69   int fd;
70 
71   loop->fs_fd = -1;
72   loop->backend_fd = -1;
73 
74   fd = port_create();
75   if (fd == -1)
76     return UV__ERR(errno);
77 
78   err = uv__cloexec(fd, 1);
79   if (err) {
80     uv__close(fd);
81     return err;
82   }
83   loop->backend_fd = fd;
84 
85   return 0;
86 }
87 
88 
uv__platform_loop_delete(uv_loop_t * loop)89 void uv__platform_loop_delete(uv_loop_t* loop) {
90   if (loop->fs_fd != -1) {
91     uv__close(loop->fs_fd);
92     loop->fs_fd = -1;
93   }
94 
95   if (loop->backend_fd != -1) {
96     uv__close(loop->backend_fd);
97     loop->backend_fd = -1;
98   }
99 }
100 
101 
uv__io_fork(uv_loop_t * loop)102 int uv__io_fork(uv_loop_t* loop) {
103 #if defined(PORT_SOURCE_FILE)
104   if (loop->fs_fd != -1) {
105     /* stop the watcher before we blow away its fileno */
106     uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
107   }
108 #endif
109   uv__platform_loop_delete(loop);
110   return uv__platform_loop_init(loop);
111 }
112 
113 
uv__platform_invalidate_fd(uv_loop_t * loop,int fd)114 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
115   struct port_event* events;
116   uintptr_t i;
117   uintptr_t nfds;
118 
119   assert(loop->watchers != NULL);
120   assert(fd >= 0);
121 
122   events = (struct port_event*) loop->watchers[loop->nwatchers];
123   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
124   if (events == NULL)
125     return;
126 
127   /* Invalidate events with same file descriptor */
128   for (i = 0; i < nfds; i++)
129     if ((int) events[i].portev_object == fd)
130       events[i].portev_object = -1;
131 }
132 
133 
uv__io_check_fd(uv_loop_t * loop,int fd)134 int uv__io_check_fd(uv_loop_t* loop, int fd) {
135   if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
136     return UV__ERR(errno);
137 
138   if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) {
139     perror("(libuv) port_dissociate()");
140     abort();
141   }
142 
143   return 0;
144 }
145 
146 
uv__io_poll(uv_loop_t * loop,int timeout)147 void uv__io_poll(uv_loop_t* loop, int timeout) {
148   struct port_event events[1024];
149   struct port_event* pe;
150   struct timespec spec;
151   QUEUE* q;
152   uv__io_t* w;
153   sigset_t* pset;
154   sigset_t set;
155   uint64_t base;
156   uint64_t diff;
157   unsigned int nfds;
158   unsigned int i;
159   int saved_errno;
160   int have_signals;
161   int nevents;
162   int count;
163   int err;
164   int fd;
165   int user_timeout;
166   int reset_timeout;
167 
168   if (loop->nfds == 0) {
169     assert(QUEUE_EMPTY(&loop->watcher_queue));
170     return;
171   }
172 
173   while (!QUEUE_EMPTY(&loop->watcher_queue)) {
174     q = QUEUE_HEAD(&loop->watcher_queue);
175     QUEUE_REMOVE(q);
176     QUEUE_INIT(q);
177 
178     w = QUEUE_DATA(q, uv__io_t, watcher_queue);
179     assert(w->pevents != 0);
180 
181     if (port_associate(loop->backend_fd,
182                        PORT_SOURCE_FD,
183                        w->fd,
184                        w->pevents,
185                        0)) {
186       perror("(libuv) port_associate()");
187       abort();
188     }
189 
190     w->events = w->pevents;
191   }
192 
193   pset = NULL;
194   if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
195     pset = &set;
196     sigemptyset(pset);
197     sigaddset(pset, SIGPROF);
198   }
199 
200   assert(timeout >= -1);
201   base = loop->time;
202   count = 48; /* Benchmarks suggest this gives the best throughput. */
203 
204   if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
205     reset_timeout = 1;
206     user_timeout = timeout;
207     timeout = 0;
208   } else {
209     reset_timeout = 0;
210   }
211 
212   for (;;) {
213     /* Only need to set the provider_entry_time if timeout != 0. The function
214      * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
215      */
216     if (timeout != 0)
217       uv__metrics_set_provider_entry_time(loop);
218 
219     if (timeout != -1) {
220       spec.tv_sec = timeout / 1000;
221       spec.tv_nsec = (timeout % 1000) * 1000000;
222     }
223 
224     /* Work around a kernel bug where nfds is not updated. */
225     events[0].portev_source = 0;
226 
227     nfds = 1;
228     saved_errno = 0;
229 
230     if (pset != NULL)
231       pthread_sigmask(SIG_BLOCK, pset, NULL);
232 
233     err = port_getn(loop->backend_fd,
234                     events,
235                     ARRAY_SIZE(events),
236                     &nfds,
237                     timeout == -1 ? NULL : &spec);
238 
239     if (pset != NULL)
240       pthread_sigmask(SIG_UNBLOCK, pset, NULL);
241 
242     if (err) {
243       /* Work around another kernel bug: port_getn() may return events even
244        * on error.
245        */
246       if (errno == EINTR || errno == ETIME) {
247         saved_errno = errno;
248       } else {
249         perror("(libuv) port_getn()");
250         abort();
251       }
252     }
253 
254     /* Update loop->time unconditionally. It's tempting to skip the update when
255      * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
256      * operating system didn't reschedule our process while in the syscall.
257      */
258     SAVE_ERRNO(uv__update_time(loop));
259 
260     if (events[0].portev_source == 0) {
261       if (reset_timeout != 0) {
262         timeout = user_timeout;
263         reset_timeout = 0;
264       }
265 
266       if (timeout == 0)
267         return;
268 
269       if (timeout == -1)
270         continue;
271 
272       goto update_timeout;
273     }
274 
275     if (nfds == 0) {
276       assert(timeout != -1);
277       return;
278     }
279 
280     have_signals = 0;
281     nevents = 0;
282 
283     assert(loop->watchers != NULL);
284     loop->watchers[loop->nwatchers] = (void*) events;
285     loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
286     for (i = 0; i < nfds; i++) {
287       pe = events + i;
288       fd = pe->portev_object;
289 
290       /* Skip invalidated events, see uv__platform_invalidate_fd */
291       if (fd == -1)
292         continue;
293 
294       assert(fd >= 0);
295       assert((unsigned) fd < loop->nwatchers);
296 
297       w = loop->watchers[fd];
298 
299       /* File descriptor that we've stopped watching, ignore. */
300       if (w == NULL)
301         continue;
302 
303       /* Run signal watchers last.  This also affects child process watchers
304        * because those are implemented in terms of signal watchers.
305        */
306       if (w == &loop->signal_io_watcher) {
307         have_signals = 1;
308       } else {
309         uv__metrics_update_idle_time(loop);
310         w->cb(loop, w, pe->portev_events);
311       }
312 
313       nevents++;
314 
315       if (w != loop->watchers[fd])
316         continue;  /* Disabled by callback. */
317 
318       /* Events Ports operates in oneshot mode, rearm timer on next run. */
319       if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
320         QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
321     }
322 
323     if (reset_timeout != 0) {
324       timeout = user_timeout;
325       reset_timeout = 0;
326     }
327 
328     if (have_signals != 0) {
329       uv__metrics_update_idle_time(loop);
330       loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
331     }
332 
333     loop->watchers[loop->nwatchers] = NULL;
334     loop->watchers[loop->nwatchers + 1] = NULL;
335 
336     if (have_signals != 0)
337       return;  /* Event loop should cycle now so don't poll again. */
338 
339     if (nevents != 0) {
340       if (nfds == ARRAY_SIZE(events) && --count != 0) {
341         /* Poll for more events but don't block this time. */
342         timeout = 0;
343         continue;
344       }
345       return;
346     }
347 
348     if (saved_errno == ETIME) {
349       assert(timeout != -1);
350       return;
351     }
352 
353     if (timeout == 0)
354       return;
355 
356     if (timeout == -1)
357       continue;
358 
359 update_timeout:
360     assert(timeout > 0);
361 
362     diff = loop->time - base;
363     if (diff >= (uint64_t) timeout)
364       return;
365 
366     timeout -= diff;
367   }
368 }
369 
370 
uv__hrtime(uv_clocktype_t type)371 uint64_t uv__hrtime(uv_clocktype_t type) {
372   return gethrtime();
373 }
374 
375 
376 /*
377  * We could use a static buffer for the path manipulations that we need outside
378  * of the function, but this function could be called by multiple consumers and
379  * we don't want to potentially create a race condition in the use of snprintf.
380  */
uv_exepath(char * buffer,size_t * size)381 int uv_exepath(char* buffer, size_t* size) {
382   ssize_t res;
383   char buf[128];
384 
385   if (buffer == NULL || size == NULL || *size == 0)
386     return UV_EINVAL;
387 
388   snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
389 
390   res = *size - 1;
391   if (res > 0)
392     res = readlink(buf, buffer, res);
393 
394   if (res == -1)
395     return UV__ERR(errno);
396 
397   buffer[res] = '\0';
398   *size = res;
399   return 0;
400 }
401 
402 
uv_get_free_memory(void)403 uint64_t uv_get_free_memory(void) {
404   return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
405 }
406 
407 
uv_get_total_memory(void)408 uint64_t uv_get_total_memory(void) {
409   return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
410 }
411 
412 
uv_get_constrained_memory(void)413 uint64_t uv_get_constrained_memory(void) {
414   return 0;  /* Memory constraints are unknown. */
415 }
416 
417 
uv_loadavg(double avg[3])418 void uv_loadavg(double avg[3]) {
419   (void) getloadavg(avg, 3);
420 }
421 
422 
423 #if defined(PORT_SOURCE_FILE)
424 
uv__fs_event_rearm(uv_fs_event_t * handle)425 static int uv__fs_event_rearm(uv_fs_event_t *handle) {
426   if (handle->fd == PORT_DELETED)
427     return UV_EBADF;
428 
429   if (port_associate(handle->loop->fs_fd,
430                      PORT_SOURCE_FILE,
431                      (uintptr_t) &handle->fo,
432                      FILE_ATTRIB | FILE_MODIFIED,
433                      handle) == -1) {
434     return UV__ERR(errno);
435   }
436   handle->fd = PORT_LOADED;
437 
438   return 0;
439 }
440 
441 
uv__fs_event_read(uv_loop_t * loop,uv__io_t * w,unsigned int revents)442 static void uv__fs_event_read(uv_loop_t* loop,
443                               uv__io_t* w,
444                               unsigned int revents) {
445   uv_fs_event_t *handle = NULL;
446   timespec_t timeout;
447   port_event_t pe;
448   int events;
449   int r;
450 
451   (void) w;
452   (void) revents;
453 
454   do {
455     uint_t n = 1;
456 
457     /*
458      * Note that our use of port_getn() here (and not port_get()) is deliberate:
459      * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
460      * causes port_get() to return success instead of ETIME when there aren't
461      * actually any events (!); by using port_getn() in lieu of port_get(),
462      * we can at least workaround the bug by checking for zero returned events
463      * and treating it as we would ETIME.
464      */
465     do {
466       memset(&timeout, 0, sizeof timeout);
467       r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
468     }
469     while (r == -1 && errno == EINTR);
470 
471     if ((r == -1 && errno == ETIME) || n == 0)
472       break;
473 
474     handle = (uv_fs_event_t*) pe.portev_user;
475     assert((r == 0) && "unexpected port_get() error");
476 
477     if (uv__is_closing(handle)) {
478       uv__handle_stop(handle);
479       uv__make_close_pending((uv_handle_t*) handle);
480       break;
481     }
482 
483     events = 0;
484     if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
485       events |= UV_CHANGE;
486     if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
487       events |= UV_RENAME;
488     assert(events != 0);
489     handle->fd = PORT_FIRED;
490     handle->cb(handle, NULL, events, 0);
491 
492     if (handle->fd != PORT_DELETED) {
493       r = uv__fs_event_rearm(handle);
494       if (r != 0)
495         handle->cb(handle, NULL, 0, r);
496     }
497   }
498   while (handle->fd != PORT_DELETED);
499 }
500 
501 
uv_fs_event_init(uv_loop_t * loop,uv_fs_event_t * handle)502 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
503   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
504   return 0;
505 }
506 
507 
uv_fs_event_start(uv_fs_event_t * handle,uv_fs_event_cb cb,const char * path,unsigned int flags)508 int uv_fs_event_start(uv_fs_event_t* handle,
509                       uv_fs_event_cb cb,
510                       const char* path,
511                       unsigned int flags) {
512   int portfd;
513   int first_run;
514   int err;
515 
516   if (uv__is_active(handle))
517     return UV_EINVAL;
518 
519   first_run = 0;
520   if (handle->loop->fs_fd == -1) {
521     portfd = port_create();
522     if (portfd == -1)
523       return UV__ERR(errno);
524     handle->loop->fs_fd = portfd;
525     first_run = 1;
526   }
527 
528   uv__handle_start(handle);
529   handle->path = uv__strdup(path);
530   handle->fd = PORT_UNUSED;
531   handle->cb = cb;
532 
533   memset(&handle->fo, 0, sizeof handle->fo);
534   handle->fo.fo_name = handle->path;
535   err = uv__fs_event_rearm(handle);
536   if (err != 0) {
537     uv_fs_event_stop(handle);
538     return err;
539   }
540 
541   if (first_run) {
542     uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
543     uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
544   }
545 
546   return 0;
547 }
548 
549 
uv__fs_event_stop(uv_fs_event_t * handle)550 static int uv__fs_event_stop(uv_fs_event_t* handle) {
551   int ret = 0;
552 
553   if (!uv__is_active(handle))
554     return 0;
555 
556   if (handle->fd == PORT_LOADED) {
557     ret = port_dissociate(handle->loop->fs_fd,
558                     PORT_SOURCE_FILE,
559                     (uintptr_t) &handle->fo);
560   }
561 
562   handle->fd = PORT_DELETED;
563   uv__free(handle->path);
564   handle->path = NULL;
565   handle->fo.fo_name = NULL;
566   if (ret == 0)
567     uv__handle_stop(handle);
568 
569   return ret;
570 }
571 
uv_fs_event_stop(uv_fs_event_t * handle)572 int uv_fs_event_stop(uv_fs_event_t* handle) {
573   (void) uv__fs_event_stop(handle);
574   return 0;
575 }
576 
uv__fs_event_close(uv_fs_event_t * handle)577 void uv__fs_event_close(uv_fs_event_t* handle) {
578   /*
579    * If we were unable to dissociate the port here, then it is most likely
580    * that there is a pending queued event. When this happens, we don't want
581    * to complete the close as it will free the underlying memory for the
582    * handle, causing a use-after-free problem when the event is processed.
583    * We defer the final cleanup until after the event is consumed in
584    * uv__fs_event_read().
585    */
586   if (uv__fs_event_stop(handle) == 0)
587     uv__make_close_pending((uv_handle_t*) handle);
588 }
589 
590 #else /* !defined(PORT_SOURCE_FILE) */
591 
uv_fs_event_init(uv_loop_t * loop,uv_fs_event_t * handle)592 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
593   return UV_ENOSYS;
594 }
595 
596 
uv_fs_event_start(uv_fs_event_t * handle,uv_fs_event_cb cb,const char * filename,unsigned int flags)597 int uv_fs_event_start(uv_fs_event_t* handle,
598                       uv_fs_event_cb cb,
599                       const char* filename,
600                       unsigned int flags) {
601   return UV_ENOSYS;
602 }
603 
604 
uv_fs_event_stop(uv_fs_event_t * handle)605 int uv_fs_event_stop(uv_fs_event_t* handle) {
606   return UV_ENOSYS;
607 }
608 
609 
uv__fs_event_close(uv_fs_event_t * handle)610 void uv__fs_event_close(uv_fs_event_t* handle) {
611   UNREACHABLE();
612 }
613 
614 #endif /* defined(PORT_SOURCE_FILE) */
615 
616 
uv_resident_set_memory(size_t * rss)617 int uv_resident_set_memory(size_t* rss) {
618   psinfo_t psinfo;
619   int err;
620   int fd;
621 
622   fd = open("/proc/self/psinfo", O_RDONLY);
623   if (fd == -1)
624     return UV__ERR(errno);
625 
626   /* FIXME(bnoordhuis) Handle EINTR. */
627   err = UV_EINVAL;
628   if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
629     *rss = (size_t)psinfo.pr_rssize * 1024;
630     err = 0;
631   }
632   uv__close(fd);
633 
634   return err;
635 }
636 
637 
uv_uptime(double * uptime)638 int uv_uptime(double* uptime) {
639   kstat_ctl_t   *kc;
640   kstat_t       *ksp;
641   kstat_named_t *knp;
642 
643   long hz = sysconf(_SC_CLK_TCK);
644 
645   kc = kstat_open();
646   if (kc == NULL)
647     return UV_EPERM;
648 
649   ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
650   if (kstat_read(kc, ksp, NULL) == -1) {
651     *uptime = -1;
652   } else {
653     knp = (kstat_named_t*)  kstat_data_lookup(ksp, (char*) "clk_intr");
654     *uptime = knp->value.ul / hz;
655   }
656   kstat_close(kc);
657 
658   return 0;
659 }
660 
661 
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)662 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
663   int           lookup_instance;
664   kstat_ctl_t   *kc;
665   kstat_t       *ksp;
666   kstat_named_t *knp;
667   uv_cpu_info_t* cpu_info;
668 
669   kc = kstat_open();
670   if (kc == NULL)
671     return UV_EPERM;
672 
673   /* Get count of cpus */
674   lookup_instance = 0;
675   while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
676     lookup_instance++;
677   }
678 
679   *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
680   if (!(*cpu_infos)) {
681     kstat_close(kc);
682     return UV_ENOMEM;
683   }
684 
685   *count = lookup_instance;
686 
687   cpu_info = *cpu_infos;
688   lookup_instance = 0;
689   while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
690     if (kstat_read(kc, ksp, NULL) == -1) {
691       cpu_info->speed = 0;
692       cpu_info->model = NULL;
693     } else {
694       knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
695       assert(knp->data_type == KSTAT_DATA_INT32 ||
696              knp->data_type == KSTAT_DATA_INT64);
697       cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
698                                                              : knp->value.i64;
699 
700       knp = kstat_data_lookup(ksp, (char*) "brand");
701       assert(knp->data_type == KSTAT_DATA_STRING);
702       cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
703     }
704 
705     lookup_instance++;
706     cpu_info++;
707   }
708 
709   cpu_info = *cpu_infos;
710   lookup_instance = 0;
711   for (;;) {
712     ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
713 
714     if (ksp == NULL)
715       break;
716 
717     if (kstat_read(kc, ksp, NULL) == -1) {
718       cpu_info->cpu_times.user = 0;
719       cpu_info->cpu_times.nice = 0;
720       cpu_info->cpu_times.sys = 0;
721       cpu_info->cpu_times.idle = 0;
722       cpu_info->cpu_times.irq = 0;
723     } else {
724       knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
725       assert(knp->data_type == KSTAT_DATA_UINT64);
726       cpu_info->cpu_times.user = knp->value.ui64;
727 
728       knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
729       assert(knp->data_type == KSTAT_DATA_UINT64);
730       cpu_info->cpu_times.sys = knp->value.ui64;
731 
732       knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
733       assert(knp->data_type == KSTAT_DATA_UINT64);
734       cpu_info->cpu_times.idle = knp->value.ui64;
735 
736       knp = kstat_data_lookup(ksp, (char*) "intr");
737       assert(knp->data_type == KSTAT_DATA_UINT64);
738       cpu_info->cpu_times.irq = knp->value.ui64;
739       cpu_info->cpu_times.nice = 0;
740     }
741 
742     lookup_instance++;
743     cpu_info++;
744   }
745 
746   kstat_close(kc);
747 
748   return 0;
749 }
750 
751 
752 #ifdef SUNOS_NO_IFADDRS
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)753 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
754   *count = 0;
755   *addresses = NULL;
756   return UV_ENOSYS;
757 }
758 #else  /* SUNOS_NO_IFADDRS */
759 /*
760  * Inspired By:
761  * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
762  * http://www.pauliesworld.org/project/getmac.c
763  */
uv__set_phys_addr(uv_interface_address_t * address,struct ifaddrs * ent)764 static int uv__set_phys_addr(uv_interface_address_t* address,
765                              struct ifaddrs* ent) {
766 
767   struct sockaddr_dl* sa_addr;
768   int sockfd;
769   size_t i;
770   struct arpreq arpreq;
771 
772   /* This appears to only work as root */
773   sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
774   memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
775   for (i = 0; i < sizeof(address->phys_addr); i++) {
776     /* Check that all bytes of phys_addr are zero. */
777     if (address->phys_addr[i] != 0)
778       return 0;
779   }
780   memset(&arpreq, 0, sizeof(arpreq));
781   if (address->address.address4.sin_family == AF_INET) {
782     struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
783     sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
784   } else if (address->address.address4.sin_family == AF_INET6) {
785     struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
786     memcpy(sin->sin6_addr.s6_addr,
787            address->address.address6.sin6_addr.s6_addr,
788            sizeof(address->address.address6.sin6_addr.s6_addr));
789   } else {
790     return 0;
791   }
792 
793   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
794   if (sockfd < 0)
795     return UV__ERR(errno);
796 
797   if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
798     uv__close(sockfd);
799     return UV__ERR(errno);
800   }
801   memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
802   uv__close(sockfd);
803   return 0;
804 }
805 
806 
uv__ifaddr_exclude(struct ifaddrs * ent)807 static int uv__ifaddr_exclude(struct ifaddrs *ent) {
808   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
809     return 1;
810   if (ent->ifa_addr == NULL)
811     return 1;
812   if (ent->ifa_addr->sa_family != AF_INET &&
813       ent->ifa_addr->sa_family != AF_INET6)
814     return 1;
815   return 0;
816 }
817 
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)818 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
819   uv_interface_address_t* address;
820   struct ifaddrs* addrs;
821   struct ifaddrs* ent;
822 
823   *count = 0;
824   *addresses = NULL;
825 
826   if (getifaddrs(&addrs))
827     return UV__ERR(errno);
828 
829   /* Count the number of interfaces */
830   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
831     if (uv__ifaddr_exclude(ent))
832       continue;
833     (*count)++;
834   }
835 
836   if (*count == 0) {
837     freeifaddrs(addrs);
838     return 0;
839   }
840 
841   *addresses = uv__malloc(*count * sizeof(**addresses));
842   if (!(*addresses)) {
843     freeifaddrs(addrs);
844     return UV_ENOMEM;
845   }
846 
847   address = *addresses;
848 
849   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
850     if (uv__ifaddr_exclude(ent))
851       continue;
852 
853     address->name = uv__strdup(ent->ifa_name);
854 
855     if (ent->ifa_addr->sa_family == AF_INET6) {
856       address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
857     } else {
858       address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
859     }
860 
861     if (ent->ifa_netmask->sa_family == AF_INET6) {
862       address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
863     } else {
864       address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
865     }
866 
867     address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
868                            (ent->ifa_flags & IFF_LOOPBACK));
869 
870     uv__set_phys_addr(address, ent);
871     address++;
872   }
873 
874   freeifaddrs(addrs);
875 
876   return 0;
877 }
878 #endif  /* SUNOS_NO_IFADDRS */
879 
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)880 void uv_free_interface_addresses(uv_interface_address_t* addresses,
881   int count) {
882   int i;
883 
884   for (i = 0; i < count; i++) {
885     uv__free(addresses[i].name);
886   }
887 
888   uv__free(addresses);
889 }
890 
891 
892 #if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
strnlen(const char * s,size_t maxlen)893 size_t strnlen(const char* s, size_t maxlen) {
894   const char* end;
895   end = memchr(s, '\0', maxlen);
896   if (end == NULL)
897     return maxlen;
898   return end - s;
899 }
900 #endif
901