1/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22#include "uv.h"
23#include "internal.h"
24
25#include <stdio.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29#include <assert.h>
30#include <errno.h>
31
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/ioctl.h>
35#include <net/if.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38
39#include <sys/time.h>
40#include <unistd.h>
41#include <fcntl.h>
42#include <utmp.h>
43#include <libgen.h>
44
45#include <sys/protosw.h>
46#include <libperfstat.h>
47#include <procinfo.h>
48#include <sys/proc.h>
49#include <sys/procfs.h>
50
51#include <sys/poll.h>
52
53#include <sys/pollset.h>
54#include <ctype.h>
55#ifdef HAVE_SYS_AHAFS_EVPRODS_H
56#include <sys/ahafs_evProds.h>
57#endif
58
59#include <sys/mntctl.h>
60#include <sys/vmount.h>
61#include <limits.h>
62#include <strings.h>
63#include <sys/vnode.h>
64
65#define RDWR_BUF_SIZE   4096
66#define EQ(a,b)         (strcmp(a,b) == 0)
67
68char* original_exepath = NULL;
69uv_mutex_t process_title_mutex;
70uv_once_t process_title_mutex_once = UV_ONCE_INIT;
71static void* args_mem = NULL;
72static char** process_argv = NULL;
73static int process_argc = 0;
74static char* process_title_ptr = NULL;
75
76void init_process_title_mutex_once(void) {
77  uv_mutex_init(&process_title_mutex);
78}
79
80
81int uv__platform_loop_init(uv_loop_t* loop) {
82  loop->fs_fd = -1;
83
84  /* Passing maxfd of -1 should mean the limit is determined
85   * by the user's ulimit or the global limit as per the doc */
86  loop->backend_fd = pollset_create(-1);
87
88  if (loop->backend_fd == -1)
89    return -1;
90
91  return 0;
92}
93
94
95void uv__platform_loop_delete(uv_loop_t* loop) {
96  if (loop->fs_fd != -1) {
97    uv__close(loop->fs_fd);
98    loop->fs_fd = -1;
99  }
100
101  if (loop->backend_fd != -1) {
102    pollset_destroy(loop->backend_fd);
103    loop->backend_fd = -1;
104  }
105}
106
107
108int uv__io_fork(uv_loop_t* loop) {
109  uv__platform_loop_delete(loop);
110
111  return uv__platform_loop_init(loop);
112}
113
114
115int uv__io_check_fd(uv_loop_t* loop, int fd) {
116  struct poll_ctl pc;
117
118  pc.events = POLLIN;
119  pc.cmd = PS_MOD;  /* Equivalent to PS_ADD if the fd is not in the pollset. */
120  pc.fd = fd;
121
122  if (pollset_ctl(loop->backend_fd, &pc, 1))
123    return UV__ERR(errno);
124
125  pc.cmd = PS_DELETE;
126  if (pollset_ctl(loop->backend_fd, &pc, 1))
127    abort();
128
129  return 0;
130}
131
132
133void uv__io_poll(uv_loop_t* loop, int timeout) {
134  struct pollfd events[1024];
135  struct pollfd pqry;
136  struct pollfd* pe;
137  struct poll_ctl pc;
138  QUEUE* q;
139  uv__io_t* w;
140  uint64_t base;
141  uint64_t diff;
142  int have_signals;
143  int nevents;
144  int count;
145  int nfds;
146  int i;
147  int rc;
148  int add_failed;
149  int user_timeout;
150  int reset_timeout;
151
152  if (loop->nfds == 0) {
153    assert(QUEUE_EMPTY(&loop->watcher_queue));
154    return;
155  }
156
157  while (!QUEUE_EMPTY(&loop->watcher_queue)) {
158    q = QUEUE_HEAD(&loop->watcher_queue);
159    QUEUE_REMOVE(q);
160    QUEUE_INIT(q);
161
162    w = QUEUE_DATA(q, uv__io_t, watcher_queue);
163    assert(w->pevents != 0);
164    assert(w->fd >= 0);
165    assert(w->fd < (int) loop->nwatchers);
166
167    pc.events = w->pevents;
168    pc.fd = w->fd;
169
170    add_failed = 0;
171    if (w->events == 0) {
172      pc.cmd = PS_ADD;
173      if (pollset_ctl(loop->backend_fd, &pc, 1)) {
174        if (errno != EINVAL) {
175          assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
176          abort();
177        }
178        /* Check if the fd is already in the pollset */
179        pqry.fd = pc.fd;
180        rc = pollset_query(loop->backend_fd, &pqry);
181        switch (rc) {
182        case -1:
183          assert(0 && "Failed to query pollset for file descriptor");
184          abort();
185        case 0:
186          assert(0 && "Pollset does not contain file descriptor");
187          abort();
188        }
189        /* If we got here then the pollset already contained the file descriptor even though
190         * we didn't think it should. This probably shouldn't happen, but we can continue. */
191        add_failed = 1;
192      }
193    }
194    if (w->events != 0 || add_failed) {
195      /* Modify, potentially removing events -- need to delete then add.
196       * Could maybe mod if we knew for sure no events are removed, but
197       * content of w->events is handled above as not reliable (falls back)
198       * so may require a pollset_query() which would have to be pretty cheap
199       * compared to a PS_DELETE to be worth optimizing. Alternatively, could
200       * lazily remove events, squelching them in the mean time. */
201      pc.cmd = PS_DELETE;
202      if (pollset_ctl(loop->backend_fd, &pc, 1)) {
203        assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
204        abort();
205      }
206      pc.cmd = PS_ADD;
207      if (pollset_ctl(loop->backend_fd, &pc, 1)) {
208        assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
209        abort();
210      }
211    }
212
213    w->events = w->pevents;
214  }
215
216  assert(timeout >= -1);
217  base = loop->time;
218  count = 48; /* Benchmarks suggest this gives the best throughput. */
219
220  if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
221    reset_timeout = 1;
222    user_timeout = timeout;
223    timeout = 0;
224  } else {
225    reset_timeout = 0;
226  }
227
228  for (;;) {
229    /* Only need to set the provider_entry_time if timeout != 0. The function
230     * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
231     */
232    if (timeout != 0)
233      uv__metrics_set_provider_entry_time(loop);
234
235    nfds = pollset_poll(loop->backend_fd,
236                        events,
237                        ARRAY_SIZE(events),
238                        timeout);
239
240    /* Update loop->time unconditionally. It's tempting to skip the update when
241     * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
242     * operating system didn't reschedule our process while in the syscall.
243     */
244    SAVE_ERRNO(uv__update_time(loop));
245
246    if (nfds == 0) {
247      if (reset_timeout != 0) {
248        timeout = user_timeout;
249        reset_timeout = 0;
250        if (timeout == -1)
251          continue;
252        if (timeout > 0)
253          goto update_timeout;
254      }
255
256      assert(timeout != -1);
257      return;
258    }
259
260    if (nfds == -1) {
261      if (errno != EINTR) {
262        abort();
263      }
264
265      if (reset_timeout != 0) {
266        timeout = user_timeout;
267        reset_timeout = 0;
268      }
269
270      if (timeout == -1)
271        continue;
272
273      if (timeout == 0)
274        return;
275
276      /* Interrupted by a signal. Update timeout and poll again. */
277      goto update_timeout;
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
287    for (i = 0; i < nfds; i++) {
288      pe = events + i;
289      pc.cmd = PS_DELETE;
290      pc.fd = pe->fd;
291
292      /* Skip invalidated events, see uv__platform_invalidate_fd */
293      if (pc.fd == -1)
294        continue;
295
296      assert(pc.fd >= 0);
297      assert((unsigned) pc.fd < loop->nwatchers);
298
299      w = loop->watchers[pc.fd];
300
301      if (w == NULL) {
302        /* File descriptor that we've stopped watching, disarm it.
303         *
304         * Ignore all errors because we may be racing with another thread
305         * when the file descriptor is closed.
306         */
307        pollset_ctl(loop->backend_fd, &pc, 1);
308        continue;
309      }
310
311      /* Run signal watchers last.  This also affects child process watchers
312       * because those are implemented in terms of signal watchers.
313       */
314      if (w == &loop->signal_io_watcher) {
315        have_signals = 1;
316      } else {
317        uv__metrics_update_idle_time(loop);
318        w->cb(loop, w, pe->revents);
319      }
320
321      nevents++;
322    }
323
324    if (reset_timeout != 0) {
325      timeout = user_timeout;
326      reset_timeout = 0;
327    }
328
329    if (have_signals != 0) {
330      uv__metrics_update_idle_time(loop);
331      loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
332    }
333
334    loop->watchers[loop->nwatchers] = NULL;
335    loop->watchers[loop->nwatchers + 1] = NULL;
336
337    if (have_signals != 0)
338      return;  /* Event loop should cycle now so don't poll again. */
339
340    if (nevents != 0) {
341      if (nfds == ARRAY_SIZE(events) && --count != 0) {
342        /* Poll for more events but don't block this time. */
343        timeout = 0;
344        continue;
345      }
346      return;
347    }
348
349    if (timeout == 0)
350      return;
351
352    if (timeout == -1)
353      continue;
354
355update_timeout:
356    assert(timeout > 0);
357
358    diff = loop->time - base;
359    if (diff >= (uint64_t) timeout)
360      return;
361
362    timeout -= diff;
363  }
364}
365
366
367uint64_t uv_get_free_memory(void) {
368  perfstat_memory_total_t mem_total;
369  int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
370  if (result == -1) {
371    return 0;
372  }
373  return mem_total.real_free * 4096;
374}
375
376
377uint64_t uv_get_total_memory(void) {
378  perfstat_memory_total_t mem_total;
379  int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
380  if (result == -1) {
381    return 0;
382  }
383  return mem_total.real_total * 4096;
384}
385
386
387uint64_t uv_get_constrained_memory(void) {
388  return 0;  /* Memory constraints are unknown. */
389}
390
391
392void uv_loadavg(double avg[3]) {
393  perfstat_cpu_total_t ps_total;
394  int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
395  if (result == -1) {
396    avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
397    return;
398  }
399  avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
400  avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
401  avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
402}
403
404
405#ifdef HAVE_SYS_AHAFS_EVPRODS_H
406static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) {
407  char* dp;
408
409  dp = rindex(cp, '/');
410  if (dp == 0)
411    return 0;
412
413  snprintf(*dst, sizeof(*dst), "%.*s/r%s", (int) (dp - cp), cp, dp + 1);
414  return *dst;
415}
416
417
418/*
419 * Determine whether given pathname is a directory
420 * Returns 0 if the path is a directory, -1 if not
421 *
422 * Note: Opportunity here for more detailed error information but
423 *       that requires changing callers of this function as well
424 */
425static int uv__path_is_a_directory(char* filename) {
426  struct stat statbuf;
427
428  if (stat(filename, &statbuf) < 0)
429    return -1;  /* failed: not a directory, assume it is a file */
430
431  if (statbuf.st_type == VDIR)
432    return 0;
433
434  return -1;
435}
436
437
438/*
439 * Check whether AHAFS is mounted.
440 * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
441 */
442static int uv__is_ahafs_mounted(void){
443  char rawbuf[FILENAME_MAX+1];
444  int rv, i = 2;
445  struct vmount *p;
446  int size_multiplier = 10;
447  size_t siz = sizeof(struct vmount)*size_multiplier;
448  struct vmount *vmt;
449  const char *dev = "/aha";
450  char *obj, *stub;
451
452  p = uv__malloc(siz);
453  if (p == NULL)
454    return UV__ERR(errno);
455
456  /* Retrieve all mounted filesystems */
457  rv = mntctl(MCTL_QUERY, siz, (char*)p);
458  if (rv < 0)
459    return UV__ERR(errno);
460  if (rv == 0) {
461    /* buffer was not large enough, reallocate to correct size */
462    siz = *(int*)p;
463    uv__free(p);
464    p = uv__malloc(siz);
465    if (p == NULL)
466      return UV__ERR(errno);
467    rv = mntctl(MCTL_QUERY, siz, (char*)p);
468    if (rv < 0)
469      return UV__ERR(errno);
470  }
471
472  /* Look for dev in filesystems mount info */
473  for(vmt = p, i = 0; i < rv; i++) {
474    obj = vmt2dataptr(vmt, VMT_OBJECT);     /* device */
475    stub = vmt2dataptr(vmt, VMT_STUB);      /* mount point */
476
477    if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) {
478      uv__free(p);  /* Found a match */
479      return 0;
480    }
481    vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
482  }
483
484  /* /aha is required for monitoring filesystem changes */
485  return -1;
486}
487
488/*
489 * Recursive call to mkdir() to create intermediate folders, if any
490 * Returns code from mkdir call
491 */
492static int uv__makedir_p(const char *dir) {
493  char tmp[256];
494  char *p = NULL;
495  size_t len;
496  int err;
497
498  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
499  uv__strscpy(tmp, dir, sizeof(tmp));
500  len = strlen(tmp);
501  if (tmp[len - 1] == '/')
502    tmp[len - 1] = 0;
503  for (p = tmp + 1; *p; p++) {
504    if (*p == '/') {
505      *p = 0;
506      err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
507      if (err != 0 && errno != EEXIST)
508        return err;
509      *p = '/';
510    }
511  }
512  return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
513}
514
515/*
516 * Creates necessary subdirectories in the AIX Event Infrastructure
517 * file system for monitoring the object specified.
518 * Returns code from mkdir call
519 */
520static int uv__make_subdirs_p(const char *filename) {
521  char cmd[2048];
522  char *p;
523  int rc = 0;
524
525  /* Strip off the monitor file name */
526  p = strrchr(filename, '/');
527
528  if (p == NULL)
529    return 0;
530
531  if (uv__path_is_a_directory((char*)filename) == 0) {
532    sprintf(cmd, "/aha/fs/modDir.monFactory");
533  } else {
534    sprintf(cmd, "/aha/fs/modFile.monFactory");
535  }
536
537  strncat(cmd, filename, (p - filename));
538  rc = uv__makedir_p(cmd);
539
540  if (rc == -1 && errno != EEXIST){
541    return UV__ERR(errno);
542  }
543
544  return rc;
545}
546
547
548/*
549 * Checks if /aha is mounted, then proceeds to set up the monitoring
550 * objects for the specified file.
551 * Returns 0 on success, or an error code < 0 on failure
552 */
553static int uv__setup_ahafs(const char* filename, int *fd) {
554  int rc = 0;
555  char mon_file_write_string[RDWR_BUF_SIZE];
556  char mon_file[PATH_MAX];
557  int file_is_directory = 0; /* -1 == NO, 0 == YES  */
558
559  /* Create monitor file name for object */
560  file_is_directory = uv__path_is_a_directory((char*)filename);
561
562  if (file_is_directory == 0)
563    sprintf(mon_file, "/aha/fs/modDir.monFactory");
564  else
565    sprintf(mon_file, "/aha/fs/modFile.monFactory");
566
567  if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
568    return UV_ENAMETOOLONG;
569
570  /* Make the necessary subdirectories for the monitor file */
571  rc = uv__make_subdirs_p(filename);
572  if (rc == -1 && errno != EEXIST)
573    return rc;
574
575  strcat(mon_file, filename);
576  strcat(mon_file, ".mon");
577
578  *fd = 0; errno = 0;
579
580  /* Open the monitor file, creating it if necessary */
581  *fd = open(mon_file, O_CREAT|O_RDWR);
582  if (*fd < 0)
583    return UV__ERR(errno);
584
585  /* Write out the monitoring specifications.
586   * In this case, we are monitoring for a state change event type
587   *    CHANGED=YES
588   * We will be waiting in select call, rather than a read:
589   *    WAIT_TYPE=WAIT_IN_SELECT
590   * We only want minimal information for files:
591   *      INFO_LVL=1
592   * For directories, we want more information to track what file
593   * caused the change
594   *      INFO_LVL=2
595   */
596
597  if (file_is_directory == 0)
598    sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
599  else
600    sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
601
602  rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
603  if (rc < 0 && errno != EBUSY)
604    return UV__ERR(errno);
605
606  return 0;
607}
608
609/*
610 * Skips a specified number of lines in the buffer passed in.
611 * Walks the buffer pointed to by p and attempts to skip n lines.
612 * Returns the total number of lines skipped
613 */
614static int uv__skip_lines(char **p, int n) {
615  int lines = 0;
616
617  while(n > 0) {
618    *p = strchr(*p, '\n');
619    if (!p)
620      return lines;
621
622    (*p)++;
623    n--;
624    lines++;
625  }
626  return lines;
627}
628
629
630/*
631 * Parse the event occurrence data to figure out what event just occurred
632 * and take proper action.
633 *
634 * The buf is a pointer to the buffer containing the event occurrence data
635 * Returns 0 on success, -1 if unrecoverable error in parsing
636 *
637 */
638static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
639  int    evp_rc, i;
640  char   *p;
641  char   filename[PATH_MAX]; /* To be used when handling directories */
642
643  p = buf;
644  *events = 0;
645
646  /* Clean the filename buffer*/
647  for(i = 0; i < PATH_MAX; i++) {
648    filename[i] = 0;
649  }
650  i = 0;
651
652  /* Check for BUF_WRAP */
653  if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
654    assert(0 && "Buffer wrap detected, Some event occurrences lost!");
655    return 0;
656  }
657
658  /* Since we are using the default buffer size (4K), and have specified
659   * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions.  Applications
660   * should check for this keyword if they are using an INFO_LVL of 2 or
661   * higher, and have a buffer size of <= 4K
662   */
663
664  /* Skip to RC_FROM_EVPROD */
665  if (uv__skip_lines(&p, 9) != 9)
666    return -1;
667
668  if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
669    if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
670      if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
671        /* The directory is no longer available for monitoring */
672        *events = UV_RENAME;
673        handle->dir_filename = NULL;
674      } else {
675        /* A file was added/removed inside the directory */
676        *events = UV_CHANGE;
677
678        /* Get the EVPROD_INFO */
679        if (uv__skip_lines(&p, 1) != 1)
680          return -1;
681
682        /* Scan out the name of the file that triggered the event*/
683        if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
684          handle->dir_filename = uv__strdup((const char*)&filename);
685        } else
686          return -1;
687        }
688    } else { /* Regular File */
689      if (evp_rc == AHAFS_MODFILE_RENAME)
690        *events = UV_RENAME;
691      else
692        *events = UV_CHANGE;
693    }
694  }
695  else
696    return -1;
697
698  return 0;
699}
700
701
702/* This is the internal callback */
703static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
704  char   result_data[RDWR_BUF_SIZE];
705  int bytes, rc = 0;
706  uv_fs_event_t* handle;
707  int events = 0;
708  char fname[PATH_MAX];
709  char *p;
710
711  handle = container_of(event_watch, uv_fs_event_t, event_watcher);
712
713  /* At this point, we assume that polling has been done on the
714   * file descriptor, so we can just read the AHAFS event occurrence
715   * data and parse its results without having to block anything
716   */
717  bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
718
719  assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
720
721  /* In file / directory move cases, AIX Event infrastructure
722   * produces a second event with no data.
723   * Ignore it and return gracefully.
724   */
725  if(bytes == 0)
726    return;
727
728  /* Parse the data */
729  if(bytes > 0)
730    rc = uv__parse_data(result_data, &events, handle);
731
732  /* Unrecoverable error */
733  if (rc == -1)
734    return;
735
736  /* For directory changes, the name of the files that triggered the change
737   * are never absolute pathnames
738   */
739  if (uv__path_is_a_directory(handle->path) == 0) {
740    p = handle->dir_filename;
741  } else {
742    p = strrchr(handle->path, '/');
743    if (p == NULL)
744      p = handle->path;
745    else
746      p++;
747  }
748
749  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
750  uv__strscpy(fname, p, sizeof(fname));
751
752  handle->cb(handle, fname, events, 0);
753}
754#endif
755
756
757int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
758#ifdef HAVE_SYS_AHAFS_EVPRODS_H
759  uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
760  return 0;
761#else
762  return UV_ENOSYS;
763#endif
764}
765
766
767int uv_fs_event_start(uv_fs_event_t* handle,
768                      uv_fs_event_cb cb,
769                      const char* filename,
770                      unsigned int flags) {
771#ifdef HAVE_SYS_AHAFS_EVPRODS_H
772  int  fd, rc, str_offset = 0;
773  char cwd[PATH_MAX];
774  char absolute_path[PATH_MAX];
775  char readlink_cwd[PATH_MAX];
776  struct timeval zt;
777  fd_set pollfd;
778
779
780  /* Figure out whether filename is absolute or not */
781  if (filename[0] == '\0') {
782    /* Missing a pathname */
783    return UV_ENOENT;
784  }
785  else if (filename[0] == '/') {
786    /* We have absolute pathname */
787    /* TODO(bnoordhuis) Check uv__strscpy() return value. */
788    uv__strscpy(absolute_path, filename, sizeof(absolute_path));
789  } else {
790    /* We have a relative pathname, compose the absolute pathname */
791    snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
792    rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1);
793    if (rc < 0)
794      return rc;
795    /* readlink does not null terminate our string */
796    readlink_cwd[rc] = '\0';
797
798    if (filename[0] == '.' && filename[1] == '/')
799      str_offset = 2;
800
801    snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd,
802             filename + str_offset);
803  }
804
805  if (uv__is_ahafs_mounted() < 0)  /* /aha checks failed */
806    return UV_ENOSYS;
807
808  /* Setup ahafs */
809  rc = uv__setup_ahafs((const char *)absolute_path, &fd);
810  if (rc != 0)
811    return rc;
812
813  /* Setup/Initialize all the libuv routines */
814  uv__handle_start(handle);
815  uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
816  handle->path = uv__strdup(filename);
817  handle->cb = cb;
818  handle->dir_filename = NULL;
819
820  uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
821
822  /* AHAFS wants someone to poll for it to start mointoring.
823   *  so kick-start it so that we don't miss an event in the
824   *  eventuality of an event that occurs in the current loop. */
825  do {
826    memset(&zt, 0, sizeof(zt));
827    FD_ZERO(&pollfd);
828    FD_SET(fd, &pollfd);
829    rc = select(fd + 1, &pollfd, NULL, NULL, &zt);
830  } while (rc == -1 && errno == EINTR);
831  return 0;
832#else
833  return UV_ENOSYS;
834#endif
835}
836
837
838int uv_fs_event_stop(uv_fs_event_t* handle) {
839#ifdef HAVE_SYS_AHAFS_EVPRODS_H
840  if (!uv__is_active(handle))
841    return 0;
842
843  uv__io_close(handle->loop, &handle->event_watcher);
844  uv__handle_stop(handle);
845
846  if (uv__path_is_a_directory(handle->path) == 0) {
847    uv__free(handle->dir_filename);
848    handle->dir_filename = NULL;
849  }
850
851  uv__free(handle->path);
852  handle->path = NULL;
853  uv__close(handle->event_watcher.fd);
854  handle->event_watcher.fd = -1;
855
856  return 0;
857#else
858  return UV_ENOSYS;
859#endif
860}
861
862
863void uv__fs_event_close(uv_fs_event_t* handle) {
864#ifdef HAVE_SYS_AHAFS_EVPRODS_H
865  uv_fs_event_stop(handle);
866#else
867  UNREACHABLE();
868#endif
869}
870
871
872char** uv_setup_args(int argc, char** argv) {
873  char exepath[UV__PATH_MAX];
874  char** new_argv;
875  size_t size;
876  char* s;
877  int i;
878
879  if (argc <= 0)
880    return argv;
881
882  /* Save the original pointer to argv.
883   * AIX uses argv to read the process name.
884   * (Not the memory pointed to by argv[0..n] as on Linux.)
885   */
886  process_argv = argv;
887  process_argc = argc;
888
889  /* Use argv[0] to determine value for uv_exepath(). */
890  size = sizeof(exepath);
891  if (uv__search_path(argv[0], exepath, &size) == 0) {
892    uv_once(&process_title_mutex_once, init_process_title_mutex_once);
893    uv_mutex_lock(&process_title_mutex);
894    original_exepath = uv__strdup(exepath);
895    uv_mutex_unlock(&process_title_mutex);
896  }
897
898  /* Calculate how much memory we need for the argv strings. */
899  size = 0;
900  for (i = 0; i < argc; i++)
901    size += strlen(argv[i]) + 1;
902
903  /* Add space for the argv pointers. */
904  size += (argc + 1) * sizeof(char*);
905
906  new_argv = uv__malloc(size);
907  if (new_argv == NULL)
908    return argv;
909  args_mem = new_argv;
910
911  /* Copy over the strings and set up the pointer table. */
912  s = (char*) &new_argv[argc + 1];
913  for (i = 0; i < argc; i++) {
914    size = strlen(argv[i]) + 1;
915    memcpy(s, argv[i], size);
916    new_argv[i] = s;
917    s += size;
918  }
919  new_argv[i] = NULL;
920
921  return new_argv;
922}
923
924
925int uv_set_process_title(const char* title) {
926  char* new_title;
927
928  /* If uv_setup_args wasn't called or failed, we can't continue. */
929  if (process_argv == NULL || args_mem == NULL)
930    return UV_ENOBUFS;
931
932  /* We cannot free this pointer when libuv shuts down,
933   * the process may still be using it.
934   */
935  new_title = uv__strdup(title);
936  if (new_title == NULL)
937    return UV_ENOMEM;
938
939  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
940  uv_mutex_lock(&process_title_mutex);
941
942  /* If this is the first time this is set,
943   * don't free and set argv[1] to NULL.
944   */
945  if (process_title_ptr != NULL)
946    uv__free(process_title_ptr);
947
948  process_title_ptr = new_title;
949
950  process_argv[0] = process_title_ptr;
951  if (process_argc > 1)
952     process_argv[1] = NULL;
953
954  uv_mutex_unlock(&process_title_mutex);
955
956  return 0;
957}
958
959
960int uv_get_process_title(char* buffer, size_t size) {
961  size_t len;
962  if (buffer == NULL || size == 0)
963    return UV_EINVAL;
964
965  /* If uv_setup_args wasn't called, we can't continue. */
966  if (process_argv == NULL)
967    return UV_ENOBUFS;
968
969  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
970  uv_mutex_lock(&process_title_mutex);
971
972  len = strlen(process_argv[0]);
973  if (size <= len) {
974    uv_mutex_unlock(&process_title_mutex);
975    return UV_ENOBUFS;
976  }
977
978  memcpy(buffer, process_argv[0], len);
979  buffer[len] = '\0';
980
981  uv_mutex_unlock(&process_title_mutex);
982
983  return 0;
984}
985
986
987void uv__process_title_cleanup(void) {
988  uv__free(args_mem);  /* Keep valgrind happy. */
989  args_mem = NULL;
990}
991
992
993int uv_resident_set_memory(size_t* rss) {
994  char pp[64];
995  psinfo_t psinfo;
996  int err;
997  int fd;
998
999  snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
1000
1001  fd = open(pp, O_RDONLY);
1002  if (fd == -1)
1003    return UV__ERR(errno);
1004
1005  /* FIXME(bnoordhuis) Handle EINTR. */
1006  err = UV_EINVAL;
1007  if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
1008    *rss = (size_t)psinfo.pr_rssize * 1024;
1009    err = 0;
1010  }
1011  uv__close(fd);
1012
1013  return err;
1014}
1015
1016
1017int uv_uptime(double* uptime) {
1018  struct utmp *utmp_buf;
1019  size_t entries = 0;
1020  time_t boot_time;
1021
1022  boot_time = 0;
1023  utmpname(UTMP_FILE);
1024
1025  setutent();
1026
1027  while ((utmp_buf = getutent()) != NULL) {
1028    if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
1029      ++entries;
1030    if (utmp_buf->ut_type == BOOT_TIME)
1031      boot_time = utmp_buf->ut_time;
1032  }
1033
1034  endutent();
1035
1036  if (boot_time == 0)
1037    return UV_ENOSYS;
1038
1039  *uptime = time(NULL) - boot_time;
1040  return 0;
1041}
1042
1043
1044int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
1045  uv_cpu_info_t* cpu_info;
1046  perfstat_cpu_total_t ps_total;
1047  perfstat_cpu_t* ps_cpus;
1048  perfstat_id_t cpu_id;
1049  int result, ncpus, idx = 0;
1050
1051  result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
1052  if (result == -1) {
1053    return UV_ENOSYS;
1054  }
1055
1056  ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
1057  if (result == -1) {
1058    return UV_ENOSYS;
1059  }
1060
1061  ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t));
1062  if (!ps_cpus) {
1063    return UV_ENOMEM;
1064  }
1065
1066  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
1067  uv__strscpy(cpu_id.name, FIRST_CPU, sizeof(cpu_id.name));
1068  result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
1069  if (result == -1) {
1070    uv__free(ps_cpus);
1071    return UV_ENOSYS;
1072  }
1073
1074  *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t));
1075  if (!*cpu_infos) {
1076    uv__free(ps_cpus);
1077    return UV_ENOMEM;
1078  }
1079
1080  *count = ncpus;
1081
1082  cpu_info = *cpu_infos;
1083  while (idx < ncpus) {
1084    cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
1085    cpu_info->model = uv__strdup(ps_total.description);
1086    cpu_info->cpu_times.user = ps_cpus[idx].user;
1087    cpu_info->cpu_times.sys = ps_cpus[idx].sys;
1088    cpu_info->cpu_times.idle = ps_cpus[idx].idle;
1089    cpu_info->cpu_times.irq = ps_cpus[idx].wait;
1090    cpu_info->cpu_times.nice = 0;
1091    cpu_info++;
1092    idx++;
1093  }
1094
1095  uv__free(ps_cpus);
1096  return 0;
1097}
1098
1099
1100int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
1101  uv_interface_address_t* address;
1102  int sockfd, sock6fd, inet6, i, r, size = 1;
1103  struct ifconf ifc;
1104  struct ifreq *ifr, *p, flg;
1105  struct in6_ifreq if6;
1106  struct sockaddr_dl* sa_addr;
1107
1108  ifc.ifc_req = NULL;
1109  sock6fd = -1;
1110  r = 0;
1111  *count = 0;
1112  *addresses = NULL;
1113
1114  if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
1115    r = UV__ERR(errno);
1116    goto cleanup;
1117  }
1118
1119  if (0 > (sock6fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP))) {
1120    r = UV__ERR(errno);
1121    goto cleanup;
1122  }
1123
1124  if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
1125    r = UV__ERR(errno);
1126    goto cleanup;
1127  }
1128
1129  ifc.ifc_req = (struct ifreq*)uv__malloc(size);
1130  if (ifc.ifc_req == NULL) {
1131    r = UV_ENOMEM;
1132    goto cleanup;
1133  }
1134  ifc.ifc_len = size;
1135  if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
1136    r = UV__ERR(errno);
1137    goto cleanup;
1138  }
1139
1140#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
1141
1142  /* Count all up and running ipv4/ipv6 addresses */
1143  ifr = ifc.ifc_req;
1144  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
1145    p = ifr;
1146    ifr = (struct ifreq*)
1147      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
1148
1149    if (!(p->ifr_addr.sa_family == AF_INET6 ||
1150          p->ifr_addr.sa_family == AF_INET))
1151      continue;
1152
1153    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
1154    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
1155      r = UV__ERR(errno);
1156      goto cleanup;
1157    }
1158
1159    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
1160      continue;
1161
1162    (*count)++;
1163  }
1164
1165  if (*count == 0)
1166    goto cleanup;
1167
1168  /* Alloc the return interface structs */
1169  *addresses = uv__calloc(*count, sizeof(**addresses));
1170  if (!(*addresses)) {
1171    r = UV_ENOMEM;
1172    goto cleanup;
1173  }
1174  address = *addresses;
1175
1176  ifr = ifc.ifc_req;
1177  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
1178    p = ifr;
1179    ifr = (struct ifreq*)
1180      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
1181
1182    if (!(p->ifr_addr.sa_family == AF_INET6 ||
1183          p->ifr_addr.sa_family == AF_INET))
1184      continue;
1185
1186    inet6 = (p->ifr_addr.sa_family == AF_INET6);
1187
1188    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
1189    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1)
1190      goto syserror;
1191
1192    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
1193      continue;
1194
1195    /* All conditions above must match count loop */
1196
1197    address->name = uv__strdup(p->ifr_name);
1198
1199    if (inet6)
1200      address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
1201    else
1202      address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
1203
1204    if (inet6) {
1205      memset(&if6, 0, sizeof(if6));
1206      r = uv__strscpy(if6.ifr_name, p->ifr_name, sizeof(if6.ifr_name));
1207      if (r == UV_E2BIG)
1208        goto cleanup;
1209      r = 0;
1210      memcpy(&if6.ifr_Addr, &p->ifr_addr, sizeof(if6.ifr_Addr));
1211      if (ioctl(sock6fd, SIOCGIFNETMASK6, &if6) == -1)
1212        goto syserror;
1213      address->netmask.netmask6 = *((struct sockaddr_in6*) &if6.ifr_Addr);
1214      /* Explicitly set family as the ioctl call appears to return it as 0. */
1215      address->netmask.netmask6.sin6_family = AF_INET6;
1216    } else {
1217      if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1)
1218        goto syserror;
1219      address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
1220      /* Explicitly set family as the ioctl call appears to return it as 0. */
1221      address->netmask.netmask4.sin_family = AF_INET;
1222    }
1223
1224    address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
1225
1226    address++;
1227  }
1228
1229  /* Fill in physical addresses. */
1230  ifr = ifc.ifc_req;
1231  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
1232    p = ifr;
1233    ifr = (struct ifreq*)
1234      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
1235
1236    if (p->ifr_addr.sa_family != AF_LINK)
1237      continue;
1238
1239    address = *addresses;
1240    for (i = 0; i < *count; i++) {
1241      if (strcmp(address->name, p->ifr_name) == 0) {
1242        sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
1243        memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
1244      }
1245      address++;
1246    }
1247  }
1248
1249#undef ADDR_SIZE
1250  goto cleanup;
1251
1252syserror:
1253  uv_free_interface_addresses(*addresses, *count);
1254  *addresses = NULL;
1255  *count = 0;
1256  r = UV_ENOSYS;
1257
1258cleanup:
1259  if (sockfd != -1)
1260    uv__close(sockfd);
1261  if (sock6fd != -1)
1262    uv__close(sock6fd);
1263  uv__free(ifc.ifc_req);
1264  return r;
1265}
1266
1267
1268void uv_free_interface_addresses(uv_interface_address_t* addresses,
1269  int count) {
1270  int i;
1271
1272  for (i = 0; i < count; ++i) {
1273    uv__free(addresses[i].name);
1274  }
1275
1276  uv__free(addresses);
1277}
1278
1279
1280void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
1281  struct pollfd* events;
1282  uintptr_t i;
1283  uintptr_t nfds;
1284  struct poll_ctl pc;
1285
1286  assert(loop->watchers != NULL);
1287  assert(fd >= 0);
1288
1289  events = (struct pollfd*) loop->watchers[loop->nwatchers];
1290  nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
1291
1292  if (events != NULL)
1293    /* Invalidate events with same file descriptor */
1294    for (i = 0; i < nfds; i++)
1295      if ((int) events[i].fd == fd)
1296        events[i].fd = -1;
1297
1298  /* Remove the file descriptor from the poll set */
1299  pc.events = 0;
1300  pc.cmd = PS_DELETE;
1301  pc.fd = fd;
1302  if(loop->backend_fd >= 0)
1303    pollset_ctl(loop->backend_fd, &pc, 1);
1304}
1305