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_get_constrained_memory(void)347 uint64_t uv_get_constrained_memory(void) {
348 return 0; /* Memory constraints are unknown. */
349 }
350
351
uv_loadavg(double avg[3])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
uv__rawname(const char * cp,char (* dst)[FILENAME_MAX+1])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 */
uv__path_is_a_directory(char * filename)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 */
uv__is_ahafs_mounted(void)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 */
uv__makedir_p(const char * dir)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 */
uv__make_subdirs_p(const char * filename)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 */
uv__setup_ahafs(const char * filename,int * fd)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 */
uv__skip_lines(char ** p,int n)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 */
uv__parse_data(char * buf,int * events,uv_fs_event_t * handle)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 */
uv__ahafs_event(uv_loop_t * loop,uv__io_t * event_watch,unsigned int fflags)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
uv_fs_event_init(uv_loop_t * loop,uv_fs_event_t * handle)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
uv_fs_event_start(uv_fs_event_t * handle,uv_fs_event_cb cb,const char * filename,unsigned int flags)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
uv_fs_event_stop(uv_fs_event_t * handle)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
uv__fs_event_close(uv_fs_event_t * handle)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
uv_setup_args(int argc,char ** argv)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
uv_set_process_title(const char * title)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
uv_get_process_title(char * buffer,size_t size)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
UV_DESTRUCTOR(static void free_args_mem (void))929 UV_DESTRUCTOR(static void free_args_mem(void)) {
930 uv__free(args_mem); /* Keep valgrind happy. */
931 args_mem = NULL;
932 }
933
934
uv_resident_set_memory(size_t * rss)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
uv_uptime(double * uptime)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
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)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
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)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
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)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
uv__platform_invalidate_fd(uv_loop_t * loop,int fd)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