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 
init_process_title_mutex_once(void)75 static void init_process_title_mutex_once(void) {
76   uv_mutex_init(&process_title_mutex);
77 }
78 
79 
uv__platform_loop_init(uv_loop_t * loop)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 
uv__platform_loop_delete(uv_loop_t * loop)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 
uv__io_fork(uv_loop_t * loop)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 
uv__io_check_fd(uv_loop_t * loop,int fd)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 
uv__io_poll(uv_loop_t * loop,int timeout)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 
uv_get_free_memory(void)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 
uv_get_total_memory(void)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 
uv_loadavg(double avg[3])347 void uv_loadavg(double avg[3]) {
348   perfstat_cpu_total_t ps_total;
349   int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
350   if (result == -1) {
351     avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
352     return;
353   }
354   avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
355   avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
356   avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
357 }
358 
359 
360 #ifdef HAVE_SYS_AHAFS_EVPRODS_H
uv__rawname(char * cp)361 static char *uv__rawname(char *cp) {
362   static char rawbuf[FILENAME_MAX+1];
363   char *dp = rindex(cp, '/');
364 
365   if (dp == 0)
366     return 0;
367 
368   *dp = 0;
369   strcpy(rawbuf, cp);
370   *dp = '/';
371   strcat(rawbuf, "/r");
372   strcat(rawbuf, dp+1);
373   return rawbuf;
374 }
375 
376 
377 /*
378  * Determine whether given pathname is a directory
379  * Returns 0 if the path is a directory, -1 if not
380  *
381  * Note: Opportunity here for more detailed error information but
382  *       that requires changing callers of this function as well
383  */
uv__path_is_a_directory(char * filename)384 static int uv__path_is_a_directory(char* filename) {
385   struct stat statbuf;
386 
387   if (stat(filename, &statbuf) < 0)
388     return -1;  /* failed: not a directory, assume it is a file */
389 
390   if (statbuf.st_type == VDIR)
391     return 0;
392 
393   return -1;
394 }
395 
396 
397 /*
398  * Check whether AHAFS is mounted.
399  * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
400  */
uv__is_ahafs_mounted(void)401 static int uv__is_ahafs_mounted(void){
402   int rv, i = 2;
403   struct vmount *p;
404   int size_multiplier = 10;
405   size_t siz = sizeof(struct vmount)*size_multiplier;
406   struct vmount *vmt;
407   const char *dev = "/aha";
408   char *obj, *stub;
409 
410   p = uv__malloc(siz);
411   if (p == NULL)
412     return UV__ERR(errno);
413 
414   /* Retrieve all mounted filesystems */
415   rv = mntctl(MCTL_QUERY, siz, (char*)p);
416   if (rv < 0)
417     return UV__ERR(errno);
418   if (rv == 0) {
419     /* buffer was not large enough, reallocate to correct size */
420     siz = *(int*)p;
421     uv__free(p);
422     p = uv__malloc(siz);
423     if (p == NULL)
424       return UV__ERR(errno);
425     rv = mntctl(MCTL_QUERY, siz, (char*)p);
426     if (rv < 0)
427       return UV__ERR(errno);
428   }
429 
430   /* Look for dev in filesystems mount info */
431   for(vmt = p, i = 0; i < rv; i++) {
432     obj = vmt2dataptr(vmt, VMT_OBJECT);     /* device */
433     stub = vmt2dataptr(vmt, VMT_STUB);      /* mount point */
434 
435     if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
436       uv__free(p);  /* Found a match */
437       return 0;
438     }
439     vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
440   }
441 
442   /* /aha is required for monitoring filesystem changes */
443   return -1;
444 }
445 
446 /*
447  * Recursive call to mkdir() to create intermediate folders, if any
448  * Returns code from mkdir call
449  */
uv__makedir_p(const char * dir)450 static int uv__makedir_p(const char *dir) {
451   char tmp[256];
452   char *p = NULL;
453   size_t len;
454   int err;
455 
456   snprintf(tmp, sizeof(tmp),"%s",dir);
457   len = strlen(tmp);
458   if (tmp[len - 1] == '/')
459     tmp[len - 1] = 0;
460   for (p = tmp + 1; *p; p++) {
461     if (*p == '/') {
462       *p = 0;
463       err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
464       if (err != 0 && errno != EEXIST)
465         return err;
466       *p = '/';
467     }
468   }
469   return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
470 }
471 
472 /*
473  * Creates necessary subdirectories in the AIX Event Infrastructure
474  * file system for monitoring the object specified.
475  * Returns code from mkdir call
476  */
uv__make_subdirs_p(const char * filename)477 static int uv__make_subdirs_p(const char *filename) {
478   char cmd[2048];
479   char *p;
480   int rc = 0;
481 
482   /* Strip off the monitor file name */
483   p = strrchr(filename, '/');
484 
485   if (p == NULL)
486     return 0;
487 
488   if (uv__path_is_a_directory((char*)filename) == 0) {
489     sprintf(cmd, "/aha/fs/modDir.monFactory");
490   } else {
491     sprintf(cmd, "/aha/fs/modFile.monFactory");
492   }
493 
494   strncat(cmd, filename, (p - filename));
495   rc = uv__makedir_p(cmd);
496 
497   if (rc == -1 && errno != EEXIST){
498     return UV__ERR(errno);
499   }
500 
501   return rc;
502 }
503 
504 
505 /*
506  * Checks if /aha is mounted, then proceeds to set up the monitoring
507  * objects for the specified file.
508  * Returns 0 on success, or an error code < 0 on failure
509  */
uv__setup_ahafs(const char * filename,int * fd)510 static int uv__setup_ahafs(const char* filename, int *fd) {
511   int rc = 0;
512   char mon_file_write_string[RDWR_BUF_SIZE];
513   char mon_file[PATH_MAX];
514   int file_is_directory = 0; /* -1 == NO, 0 == YES  */
515 
516   /* Create monitor file name for object */
517   file_is_directory = uv__path_is_a_directory((char*)filename);
518 
519   if (file_is_directory == 0)
520     sprintf(mon_file, "/aha/fs/modDir.monFactory");
521   else
522     sprintf(mon_file, "/aha/fs/modFile.monFactory");
523 
524   if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
525     return UV_ENAMETOOLONG;
526 
527   /* Make the necessary subdirectories for the monitor file */
528   rc = uv__make_subdirs_p(filename);
529   if (rc == -1 && errno != EEXIST)
530     return rc;
531 
532   strcat(mon_file, filename);
533   strcat(mon_file, ".mon");
534 
535   *fd = 0; errno = 0;
536 
537   /* Open the monitor file, creating it if necessary */
538   *fd = open(mon_file, O_CREAT|O_RDWR);
539   if (*fd < 0)
540     return UV__ERR(errno);
541 
542   /* Write out the monitoring specifications.
543    * In this case, we are monitoring for a state change event type
544    *    CHANGED=YES
545    * We will be waiting in select call, rather than a read:
546    *    WAIT_TYPE=WAIT_IN_SELECT
547    * We only want minimal information for files:
548    *      INFO_LVL=1
549    * For directories, we want more information to track what file
550    * caused the change
551    *      INFO_LVL=2
552    */
553 
554   if (file_is_directory == 0)
555     sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
556   else
557     sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
558 
559   rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
560   if (rc < 0)
561     return UV__ERR(errno);
562 
563   return 0;
564 }
565 
566 /*
567  * Skips a specified number of lines in the buffer passed in.
568  * Walks the buffer pointed to by p and attempts to skip n lines.
569  * Returns the total number of lines skipped
570  */
uv__skip_lines(char ** p,int n)571 static int uv__skip_lines(char **p, int n) {
572   int lines = 0;
573 
574   while(n > 0) {
575     *p = strchr(*p, '\n');
576     if (!p)
577       return lines;
578 
579     (*p)++;
580     n--;
581     lines++;
582   }
583   return lines;
584 }
585 
586 
587 /*
588  * Parse the event occurrence data to figure out what event just occurred
589  * and take proper action.
590  *
591  * The buf is a pointer to the buffer containing the event occurrence data
592  * Returns 0 on success, -1 if unrecoverable error in parsing
593  *
594  */
uv__parse_data(char * buf,int * events,uv_fs_event_t * handle)595 static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
596   int    evp_rc, i;
597   char   *p;
598   char   filename[PATH_MAX]; /* To be used when handling directories */
599 
600   p = buf;
601   *events = 0;
602 
603   /* Clean the filename buffer*/
604   for(i = 0; i < PATH_MAX; i++) {
605     filename[i] = 0;
606   }
607   i = 0;
608 
609   /* Check for BUF_WRAP */
610   if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
611     assert(0 && "Buffer wrap detected, Some event occurrences lost!");
612     return 0;
613   }
614 
615   /* Since we are using the default buffer size (4K), and have specified
616    * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions.  Applications
617    * should check for this keyword if they are using an INFO_LVL of 2 or
618    * higher, and have a buffer size of <= 4K
619    */
620 
621   /* Skip to RC_FROM_EVPROD */
622   if (uv__skip_lines(&p, 9) != 9)
623     return -1;
624 
625   if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
626     if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
627       if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
628         /* The directory is no longer available for monitoring */
629         *events = UV_RENAME;
630         handle->dir_filename = NULL;
631       } else {
632         /* A file was added/removed inside the directory */
633         *events = UV_CHANGE;
634 
635         /* Get the EVPROD_INFO */
636         if (uv__skip_lines(&p, 1) != 1)
637           return -1;
638 
639         /* Scan out the name of the file that triggered the event*/
640         if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
641           handle->dir_filename = uv__strdup((const char*)&filename);
642         } else
643           return -1;
644         }
645     } else { /* Regular File */
646       if (evp_rc == AHAFS_MODFILE_RENAME)
647         *events = UV_RENAME;
648       else
649         *events = UV_CHANGE;
650     }
651   }
652   else
653     return -1;
654 
655   return 0;
656 }
657 
658 
659 /* This is the internal callback */
uv__ahafs_event(uv_loop_t * loop,uv__io_t * event_watch,unsigned int fflags)660 static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
661   char   result_data[RDWR_BUF_SIZE];
662   int bytes, rc = 0;
663   uv_fs_event_t* handle;
664   int events = 0;
665   char fname[PATH_MAX];
666   char *p;
667 
668   handle = container_of(event_watch, uv_fs_event_t, event_watcher);
669 
670   /* At this point, we assume that polling has been done on the
671    * file descriptor, so we can just read the AHAFS event occurrence
672    * data and parse its results without having to block anything
673    */
674   bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
675 
676   assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
677 
678   /* In file / directory move cases, AIX Event infrastructure
679    * produces a second event with no data.
680    * Ignore it and return gracefully.
681    */
682   if(bytes == 0)
683     return;
684 
685   /* Parse the data */
686   if(bytes > 0)
687     rc = uv__parse_data(result_data, &events, handle);
688 
689   /* Unrecoverable error */
690   if (rc == -1)
691     return;
692 
693   /* For directory changes, the name of the files that triggered the change
694    * are never absolute pathnames
695    */
696   if (uv__path_is_a_directory(handle->path) == 0) {
697     p = handle->dir_filename;
698   } else {
699     p = strrchr(handle->path, '/');
700     if (p == NULL)
701       p = handle->path;
702     else
703       p++;
704   }
705   strncpy(fname, p, sizeof(fname) - 1);
706   /* Just in case */
707   fname[sizeof(fname) - 1] = '\0';
708 
709   handle->cb(handle, fname, events, 0);
710 }
711 #endif
712 
713 
uv_fs_event_init(uv_loop_t * loop,uv_fs_event_t * handle)714 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
715 #ifdef HAVE_SYS_AHAFS_EVPRODS_H
716   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
717   return 0;
718 #else
719   return UV_ENOSYS;
720 #endif
721 }
722 
723 
uv_fs_event_start(uv_fs_event_t * handle,uv_fs_event_cb cb,const char * filename,unsigned int flags)724 int uv_fs_event_start(uv_fs_event_t* handle,
725                       uv_fs_event_cb cb,
726                       const char* filename,
727                       unsigned int flags) {
728 #ifdef HAVE_SYS_AHAFS_EVPRODS_H
729   int  fd, rc, str_offset = 0;
730   char cwd[PATH_MAX];
731   char absolute_path[PATH_MAX];
732   char readlink_cwd[PATH_MAX];
733 
734 
735   /* Figure out whether filename is absolute or not */
736   if (filename[0] == '/') {
737     /* We have absolute pathname */
738     snprintf(absolute_path, sizeof(absolute_path), "%s", filename);
739   } else {
740     /* We have a relative pathname, compose the absolute pathname */
741     snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
742     rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1);
743     if (rc < 0)
744       return rc;
745     /* readlink does not null terminate our string */
746     readlink_cwd[rc] = '\0';
747 
748     if (filename[0] == '.' && filename[1] == '/')
749       str_offset = 2;
750 
751     snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd,
752              filename + str_offset);
753   }
754 
755   if (uv__is_ahafs_mounted() < 0)  /* /aha checks failed */
756     return UV_ENOSYS;
757 
758   /* Setup ahafs */
759   rc = uv__setup_ahafs((const char *)absolute_path, &fd);
760   if (rc != 0)
761     return rc;
762 
763   /* Setup/Initialize all the libuv routines */
764   uv__handle_start(handle);
765   uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
766   handle->path = uv__strdup(filename);
767   handle->cb = cb;
768   handle->dir_filename = NULL;
769 
770   uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
771 
772   return 0;
773 #else
774   return UV_ENOSYS;
775 #endif
776 }
777 
778 
uv_fs_event_stop(uv_fs_event_t * handle)779 int uv_fs_event_stop(uv_fs_event_t* handle) {
780 #ifdef HAVE_SYS_AHAFS_EVPRODS_H
781   if (!uv__is_active(handle))
782     return 0;
783 
784   uv__io_close(handle->loop, &handle->event_watcher);
785   uv__handle_stop(handle);
786 
787   if (uv__path_is_a_directory(handle->path) == 0) {
788     uv__free(handle->dir_filename);
789     handle->dir_filename = NULL;
790   }
791 
792   uv__free(handle->path);
793   handle->path = NULL;
794   uv__close(handle->event_watcher.fd);
795   handle->event_watcher.fd = -1;
796 
797   return 0;
798 #else
799   return UV_ENOSYS;
800 #endif
801 }
802 
803 
uv__fs_event_close(uv_fs_event_t * handle)804 void uv__fs_event_close(uv_fs_event_t* handle) {
805 #ifdef HAVE_SYS_AHAFS_EVPRODS_H
806   uv_fs_event_stop(handle);
807 #else
808   UNREACHABLE();
809 #endif
810 }
811 
812 
uv_setup_args(int argc,char ** argv)813 char** uv_setup_args(int argc, char** argv) {
814   char** new_argv;
815   size_t size;
816   char* s;
817   int i;
818 
819   if (argc <= 0)
820     return argv;
821 
822   /* Save the original pointer to argv.
823    * AIX uses argv to read the process name.
824    * (Not the memory pointed to by argv[0..n] as on Linux.)
825    */
826   process_argv = argv;
827   process_argc = argc;
828 
829   /* Calculate how much memory we need for the argv strings. */
830   size = 0;
831   for (i = 0; i < argc; i++)
832     size += strlen(argv[i]) + 1;
833 
834   /* Add space for the argv pointers. */
835   size += (argc + 1) * sizeof(char*);
836 
837   new_argv = uv__malloc(size);
838   if (new_argv == NULL)
839     return argv;
840   args_mem = new_argv;
841 
842   /* Copy over the strings and set up the pointer table. */
843   s = (char*) &new_argv[argc + 1];
844   for (i = 0; i < argc; i++) {
845     size = strlen(argv[i]) + 1;
846     memcpy(s, argv[i], size);
847     new_argv[i] = s;
848     s += size;
849   }
850   new_argv[i] = NULL;
851 
852   return new_argv;
853 }
854 
855 
uv_set_process_title(const char * title)856 int uv_set_process_title(const char* title) {
857   char* new_title;
858 
859   /* We cannot free this pointer when libuv shuts down,
860    * the process may still be using it.
861    */
862   new_title = uv__strdup(title);
863   if (new_title == NULL)
864     return UV_ENOMEM;
865 
866   uv_once(&process_title_mutex_once, init_process_title_mutex_once);
867   uv_mutex_lock(&process_title_mutex);
868 
869   /* If this is the first time this is set,
870    * don't free and set argv[1] to NULL.
871    */
872   if (process_title_ptr != NULL)
873     uv__free(process_title_ptr);
874 
875   process_title_ptr = new_title;
876 
877   process_argv[0] = process_title_ptr;
878   if (process_argc > 1)
879      process_argv[1] = NULL;
880 
881   uv_mutex_unlock(&process_title_mutex);
882 
883   return 0;
884 }
885 
886 
uv_get_process_title(char * buffer,size_t size)887 int uv_get_process_title(char* buffer, size_t size) {
888   size_t len;
889   len = strlen(process_argv[0]);
890   if (buffer == NULL || size == 0)
891     return UV_EINVAL;
892   else if (size <= len)
893     return UV_ENOBUFS;
894 
895   uv_once(&process_title_mutex_once, init_process_title_mutex_once);
896   uv_mutex_lock(&process_title_mutex);
897 
898   memcpy(buffer, process_argv[0], len + 1);
899 
900   uv_mutex_unlock(&process_title_mutex);
901 
902   return 0;
903 }
904 
905 
UV_DESTRUCTOR(static void free_args_mem (void))906 UV_DESTRUCTOR(static void free_args_mem(void)) {
907   uv__free(args_mem);  /* Keep valgrind happy. */
908   args_mem = NULL;
909 }
910 
911 
uv_resident_set_memory(size_t * rss)912 int uv_resident_set_memory(size_t* rss) {
913   char pp[64];
914   psinfo_t psinfo;
915   int err;
916   int fd;
917 
918   snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
919 
920   fd = open(pp, O_RDONLY);
921   if (fd == -1)
922     return UV__ERR(errno);
923 
924   /* FIXME(bnoordhuis) Handle EINTR. */
925   err = UV_EINVAL;
926   if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
927     *rss = (size_t)psinfo.pr_rssize * 1024;
928     err = 0;
929   }
930   uv__close(fd);
931 
932   return err;
933 }
934 
935 
uv_uptime(double * uptime)936 int uv_uptime(double* uptime) {
937   struct utmp *utmp_buf;
938   size_t entries = 0;
939   time_t boot_time;
940 
941   boot_time = 0;
942   utmpname(UTMP_FILE);
943 
944   setutent();
945 
946   while ((utmp_buf = getutent()) != NULL) {
947     if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
948       ++entries;
949     if (utmp_buf->ut_type == BOOT_TIME)
950       boot_time = utmp_buf->ut_time;
951   }
952 
953   endutent();
954 
955   if (boot_time == 0)
956     return UV_ENOSYS;
957 
958   *uptime = time(NULL) - boot_time;
959   return 0;
960 }
961 
962 
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)963 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
964   uv_cpu_info_t* cpu_info;
965   perfstat_cpu_total_t ps_total;
966   perfstat_cpu_t* ps_cpus;
967   perfstat_id_t cpu_id;
968   int result, ncpus, idx = 0;
969 
970   result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
971   if (result == -1) {
972     return UV_ENOSYS;
973   }
974 
975   ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
976   if (result == -1) {
977     return UV_ENOSYS;
978   }
979 
980   ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t));
981   if (!ps_cpus) {
982     return UV_ENOMEM;
983   }
984 
985   strcpy(cpu_id.name, FIRST_CPU);
986   result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
987   if (result == -1) {
988     uv__free(ps_cpus);
989     return UV_ENOSYS;
990   }
991 
992   *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t));
993   if (!*cpu_infos) {
994     uv__free(ps_cpus);
995     return UV_ENOMEM;
996   }
997 
998   *count = ncpus;
999 
1000   cpu_info = *cpu_infos;
1001   while (idx < ncpus) {
1002     cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
1003     cpu_info->model = uv__strdup(ps_total.description);
1004     cpu_info->cpu_times.user = ps_cpus[idx].user;
1005     cpu_info->cpu_times.sys = ps_cpus[idx].sys;
1006     cpu_info->cpu_times.idle = ps_cpus[idx].idle;
1007     cpu_info->cpu_times.irq = ps_cpus[idx].wait;
1008     cpu_info->cpu_times.nice = 0;
1009     cpu_info++;
1010     idx++;
1011   }
1012 
1013   uv__free(ps_cpus);
1014   return 0;
1015 }
1016 
1017 
uv__platform_invalidate_fd(uv_loop_t * loop,int fd)1018 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
1019   struct pollfd* events;
1020   uintptr_t i;
1021   uintptr_t nfds;
1022   struct poll_ctl pc;
1023 
1024   assert(loop->watchers != NULL);
1025 
1026   events = (struct pollfd*) loop->watchers[loop->nwatchers];
1027   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
1028 
1029   if (events != NULL)
1030     /* Invalidate events with same file descriptor */
1031     for (i = 0; i < nfds; i++)
1032       if ((int) events[i].fd == fd)
1033         events[i].fd = -1;
1034 
1035   /* Remove the file descriptor from the poll set */
1036   pc.events = 0;
1037   pc.cmd = PS_DELETE;
1038   pc.fd = fd;
1039   if(loop->backend_fd >= 0)
1040     pollset_ctl(loop->backend_fd, &pc, 1);
1041 }
1042