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