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