PageRenderTime 67ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/deps/uv/src/unix/aix.c

https://gitlab.com/GeekSir/node
C | 1240 lines | 828 code | 233 blank | 179 comment | 266 complexity | 0d67565245b87ef3edf6e44d1158fa74 MD5 | raw file
Possible License(s): 0BSD, Apache-2.0, MPL-2.0-no-copyleft-exception, JSON, WTFPL, CC-BY-SA-3.0, Unlicense, ISC, BSD-3-Clause, MIT, AGPL-3.0
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2. * Permission is hereby granted, free of charge, to any person obtaining a copy
  3. * of this software and associated documentation files (the "Software"), to
  4. * deal in the Software without restriction, including without limitation the
  5. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  6. * sell copies of the Software, and to permit persons to whom the Software is
  7. * furnished to do so, subject to the following conditions:
  8. *
  9. * The above copyright notice and this permission notice shall be included in
  10. * all copies or substantial portions of the Software.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  17. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  18. * IN THE SOFTWARE.
  19. */
  20. #include "uv.h"
  21. #include "internal.h"
  22. #include <stdio.h>
  23. #include <stdint.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <assert.h>
  27. #include <errno.h>
  28. #include <sys/types.h>
  29. #include <sys/socket.h>
  30. #include <sys/ioctl.h>
  31. #include <net/if.h>
  32. #include <netinet/in.h>
  33. #include <arpa/inet.h>
  34. #include <sys/time.h>
  35. #include <unistd.h>
  36. #include <fcntl.h>
  37. #include <utmp.h>
  38. #include <libgen.h>
  39. #include <sys/protosw.h>
  40. #include <libperfstat.h>
  41. #include <sys/proc.h>
  42. #include <sys/procfs.h>
  43. #include <sys/poll.h>
  44. #include <sys/pollset.h>
  45. #include <ctype.h>
  46. #include <sys/ahafs_evProds.h>
  47. #include <sys/mntctl.h>
  48. #include <sys/vmount.h>
  49. #include <limits.h>
  50. #include <strings.h>
  51. #include <sys/vnode.h>
  52. #define RDWR_BUF_SIZE 4096
  53. #define EQ(a,b) (strcmp(a,b) == 0)
  54. int uv__platform_loop_init(uv_loop_t* loop) {
  55. loop->fs_fd = -1;
  56. /* Passing maxfd of -1 should mean the limit is determined
  57. * by the user's ulimit or the global limit as per the doc */
  58. loop->backend_fd = pollset_create(-1);
  59. if (loop->backend_fd == -1)
  60. return -1;
  61. return 0;
  62. }
  63. void uv__platform_loop_delete(uv_loop_t* loop) {
  64. if (loop->fs_fd != -1) {
  65. uv__close(loop->fs_fd);
  66. loop->fs_fd = -1;
  67. }
  68. if (loop->backend_fd != -1) {
  69. pollset_destroy(loop->backend_fd);
  70. loop->backend_fd = -1;
  71. }
  72. }
  73. void uv__io_poll(uv_loop_t* loop, int timeout) {
  74. struct pollfd events[1024];
  75. struct pollfd pqry;
  76. struct pollfd* pe;
  77. struct poll_ctl pc;
  78. QUEUE* q;
  79. uv__io_t* w;
  80. uint64_t base;
  81. uint64_t diff;
  82. int nevents;
  83. int count;
  84. int nfds;
  85. int i;
  86. int rc;
  87. int add_failed;
  88. if (loop->nfds == 0) {
  89. assert(QUEUE_EMPTY(&loop->watcher_queue));
  90. return;
  91. }
  92. while (!QUEUE_EMPTY(&loop->watcher_queue)) {
  93. q = QUEUE_HEAD(&loop->watcher_queue);
  94. QUEUE_REMOVE(q);
  95. QUEUE_INIT(q);
  96. w = QUEUE_DATA(q, uv__io_t, watcher_queue);
  97. assert(w->pevents != 0);
  98. assert(w->fd >= 0);
  99. assert(w->fd < (int) loop->nwatchers);
  100. pc.events = w->pevents;
  101. pc.fd = w->fd;
  102. add_failed = 0;
  103. if (w->events == 0) {
  104. pc.cmd = PS_ADD;
  105. if (pollset_ctl(loop->backend_fd, &pc, 1)) {
  106. if (errno != EINVAL) {
  107. assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
  108. abort();
  109. }
  110. /* Check if the fd is already in the pollset */
  111. pqry.fd = pc.fd;
  112. rc = pollset_query(loop->backend_fd, &pqry);
  113. switch (rc) {
  114. case -1:
  115. assert(0 && "Failed to query pollset for file descriptor");
  116. abort();
  117. case 0:
  118. assert(0 && "Pollset does not contain file descriptor");
  119. abort();
  120. }
  121. /* If we got here then the pollset already contained the file descriptor even though
  122. * we didn't think it should. This probably shouldn't happen, but we can continue. */
  123. add_failed = 1;
  124. }
  125. }
  126. if (w->events != 0 || add_failed) {
  127. /* Modify, potentially removing events -- need to delete then add.
  128. * Could maybe mod if we knew for sure no events are removed, but
  129. * content of w->events is handled above as not reliable (falls back)
  130. * so may require a pollset_query() which would have to be pretty cheap
  131. * compared to a PS_DELETE to be worth optimizing. Alternatively, could
  132. * lazily remove events, squelching them in the mean time. */
  133. pc.cmd = PS_DELETE;
  134. if (pollset_ctl(loop->backend_fd, &pc, 1)) {
  135. assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
  136. abort();
  137. }
  138. pc.cmd = PS_ADD;
  139. if (pollset_ctl(loop->backend_fd, &pc, 1)) {
  140. assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
  141. abort();
  142. }
  143. }
  144. w->events = w->pevents;
  145. }
  146. assert(timeout >= -1);
  147. base = loop->time;
  148. count = 48; /* Benchmarks suggest this gives the best throughput. */
  149. for (;;) {
  150. nfds = pollset_poll(loop->backend_fd,
  151. events,
  152. ARRAY_SIZE(events),
  153. timeout);
  154. /* Update loop->time unconditionally. It's tempting to skip the update when
  155. * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
  156. * operating system didn't reschedule our process while in the syscall.
  157. */
  158. SAVE_ERRNO(uv__update_time(loop));
  159. if (nfds == 0) {
  160. assert(timeout != -1);
  161. return;
  162. }
  163. if (nfds == -1) {
  164. if (errno != EINTR) {
  165. abort();
  166. }
  167. if (timeout == -1)
  168. continue;
  169. if (timeout == 0)
  170. return;
  171. /* Interrupted by a signal. Update timeout and poll again. */
  172. goto update_timeout;
  173. }
  174. nevents = 0;
  175. assert(loop->watchers != NULL);
  176. loop->watchers[loop->nwatchers] = (void*) events;
  177. loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
  178. for (i = 0; i < nfds; i++) {
  179. pe = events + i;
  180. pc.cmd = PS_DELETE;
  181. pc.fd = pe->fd;
  182. /* Skip invalidated events, see uv__platform_invalidate_fd */
  183. if (pc.fd == -1)
  184. continue;
  185. assert(pc.fd >= 0);
  186. assert((unsigned) pc.fd < loop->nwatchers);
  187. w = loop->watchers[pc.fd];
  188. if (w == NULL) {
  189. /* File descriptor that we've stopped watching, disarm it.
  190. *
  191. * Ignore all errors because we may be racing with another thread
  192. * when the file descriptor is closed.
  193. */
  194. pollset_ctl(loop->backend_fd, &pc, 1);
  195. continue;
  196. }
  197. w->cb(loop, w, pe->revents);
  198. nevents++;
  199. }
  200. loop->watchers[loop->nwatchers] = NULL;
  201. loop->watchers[loop->nwatchers + 1] = NULL;
  202. if (nevents != 0) {
  203. if (nfds == ARRAY_SIZE(events) && --count != 0) {
  204. /* Poll for more events but don't block this time. */
  205. timeout = 0;
  206. continue;
  207. }
  208. return;
  209. }
  210. if (timeout == 0)
  211. return;
  212. if (timeout == -1)
  213. continue;
  214. update_timeout:
  215. assert(timeout > 0);
  216. diff = loop->time - base;
  217. if (diff >= (uint64_t) timeout)
  218. return;
  219. timeout -= diff;
  220. }
  221. }
  222. uint64_t uv__hrtime(uv_clocktype_t type) {
  223. uint64_t G = 1000000000;
  224. timebasestruct_t t;
  225. read_wall_time(&t, TIMEBASE_SZ);
  226. time_base_to_time(&t, TIMEBASE_SZ);
  227. return (uint64_t) t.tb_high * G + t.tb_low;
  228. }
  229. /*
  230. * We could use a static buffer for the path manipulations that we need outside
  231. * of the function, but this function could be called by multiple consumers and
  232. * we don't want to potentially create a race condition in the use of snprintf.
  233. * There is no direct way of getting the exe path in AIX - either through /procfs
  234. * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
  235. * and use it in conjunction with PATH environment variable to craft one.
  236. */
  237. int uv_exepath(char* buffer, size_t* size) {
  238. ssize_t res;
  239. char cwd[PATH_MAX], cwdl[PATH_MAX];
  240. char symlink[PATH_MAX], temp_buffer[PATH_MAX];
  241. char pp[64];
  242. struct psinfo ps;
  243. int fd;
  244. char **argv;
  245. if (buffer == NULL || size == NULL || *size == 0)
  246. return -EINVAL;
  247. snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
  248. fd = open(pp, O_RDONLY);
  249. if (fd < 0)
  250. return fd;
  251. res = read(fd, &ps, sizeof(ps));
  252. uv__close(fd);
  253. if (res < 0)
  254. return res;
  255. if (ps.pr_argv == 0)
  256. return -EINVAL;
  257. argv = (char **) *((char ***) (intptr_t) ps.pr_argv);
  258. if ((argv == NULL) || (argv[0] == NULL))
  259. return -EINVAL;
  260. /*
  261. * Three possibilities for argv[0]:
  262. * i) an absolute path such as: /home/user/myprojects/nodejs/node
  263. * ii) a relative path such as: ./node or ./myprojects/nodejs/node
  264. * iii) a bare filename such as "node", after exporting PATH variable
  265. * to its location.
  266. */
  267. /* case #1, absolute path. */
  268. if (argv[0][0] == '/') {
  269. snprintf(symlink, PATH_MAX-1, "%s", argv[0]);
  270. /* This could or could not be a symlink. */
  271. res = readlink(symlink, temp_buffer, PATH_MAX-1);
  272. /* if readlink fails, it is a normal file just copy symlink to the
  273. * output buffer.
  274. */
  275. if (res < 0) {
  276. assert(*size > strlen(symlink));
  277. strcpy(buffer, symlink);
  278. /* If it is a link, the resolved filename is again a relative path,
  279. * make it absolute.
  280. */
  281. } else {
  282. assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
  283. snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
  284. }
  285. *size = strlen(buffer);
  286. return 0;
  287. /* case #2, relative path with usage of '.' */
  288. } else if (argv[0][0] == '.') {
  289. char *relative = strchr(argv[0], '/');
  290. if (relative == NULL)
  291. return -EINVAL;
  292. /* Get the current working directory to resolve the relative path. */
  293. snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
  294. /* This is always a symlink, resolve it. */
  295. res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
  296. if (res < 0)
  297. return -errno;
  298. snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1);
  299. res = readlink(symlink, temp_buffer, PATH_MAX-1);
  300. if (res < 0) {
  301. assert(*size > strlen(symlink));
  302. strcpy(buffer, symlink);
  303. } else {
  304. assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
  305. snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
  306. }
  307. *size = strlen(buffer);
  308. return 0;
  309. /* case #3, relative path without usage of '.', such as invocations in Node test suite. */
  310. } else if (strchr(argv[0], '/') != NULL) {
  311. /* Get the current working directory to resolve the relative path. */
  312. snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
  313. /* This is always a symlink, resolve it. */
  314. res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
  315. if (res < 0)
  316. return -errno;
  317. snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]);
  318. res = readlink(symlink, temp_buffer, PATH_MAX-1);
  319. if (res < 0) {
  320. assert(*size > strlen(symlink));
  321. strcpy(buffer, symlink);
  322. } else {
  323. assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
  324. snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
  325. }
  326. *size = strlen(buffer);
  327. return 0;
  328. /* Usage of absolute filename with location exported in PATH */
  329. } else {
  330. char clonedpath[8192]; /* assume 8k buffer will fit PATH */
  331. char *token = NULL;
  332. struct stat statstruct;
  333. /* Get the paths. */
  334. char *path = getenv("PATH");
  335. if(sizeof(clonedpath) <= strlen(path))
  336. return -EINVAL;
  337. /* Get a local copy. */
  338. strcpy(clonedpath, path);
  339. /* Tokenize. */
  340. token = strtok(clonedpath, ":");
  341. /* Get current working directory. (may be required in the loop). */
  342. snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
  343. res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
  344. if (res < 0)
  345. return -errno;
  346. /* Run through the tokens, append our executable file name with each,
  347. * and see which one succeeds. Exit on first match. */
  348. while(token != NULL) {
  349. if (token[0] == '.') {
  350. /* Path contains a token relative to current directory. */
  351. char *relative = strchr(token, '/');
  352. if (relative != NULL)
  353. /* A path which is not current directory. */
  354. snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname);
  355. else
  356. snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname);
  357. if (stat(symlink, &statstruct) != -1) {
  358. /* File exists. Resolve if it is a link. */
  359. res = readlink(symlink, temp_buffer, PATH_MAX-1);
  360. if (res < 0) {
  361. assert(*size > strlen(symlink));
  362. strcpy(buffer, symlink);
  363. } else {
  364. assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
  365. snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
  366. }
  367. *size = strlen(buffer);
  368. return 0;
  369. }
  370. /* Absolute path names. */
  371. } else {
  372. snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname);
  373. if (stat(symlink, &statstruct) != -1) {
  374. res = readlink(symlink, temp_buffer, PATH_MAX-1);
  375. if (res < 0) {
  376. assert(*size > strlen(symlink));
  377. strcpy(buffer, symlink);
  378. } else {
  379. assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
  380. snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
  381. }
  382. *size = strlen(buffer);
  383. return 0;
  384. }
  385. }
  386. token = strtok(NULL, ":");
  387. }
  388. /* Out of tokens (path entries), and no match found */
  389. return -EINVAL;
  390. }
  391. }
  392. uint64_t uv_get_free_memory(void) {
  393. perfstat_memory_total_t mem_total;
  394. int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
  395. if (result == -1) {
  396. return 0;
  397. }
  398. return mem_total.real_free * 4096;
  399. }
  400. uint64_t uv_get_total_memory(void) {
  401. perfstat_memory_total_t mem_total;
  402. int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
  403. if (result == -1) {
  404. return 0;
  405. }
  406. return mem_total.real_total * 4096;
  407. }
  408. void uv_loadavg(double avg[3]) {
  409. perfstat_cpu_total_t ps_total;
  410. int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
  411. if (result == -1) {
  412. avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
  413. return;
  414. }
  415. avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
  416. avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
  417. avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
  418. }
  419. static char *uv__rawname(char *cp) {
  420. static char rawbuf[FILENAME_MAX+1];
  421. char *dp = rindex(cp, '/');
  422. if (dp == 0)
  423. return 0;
  424. *dp = 0;
  425. strcpy(rawbuf, cp);
  426. *dp = '/';
  427. strcat(rawbuf, "/r");
  428. strcat(rawbuf, dp+1);
  429. return rawbuf;
  430. }
  431. /*
  432. * Determine whether given pathname is a directory
  433. * Returns 0 if the path is a directory, -1 if not
  434. *
  435. * Note: Opportunity here for more detailed error information but
  436. * that requires changing callers of this function as well
  437. */
  438. static int uv__path_is_a_directory(char* filename) {
  439. struct stat statbuf;
  440. if (stat(filename, &statbuf) < 0)
  441. return -1; /* failed: not a directory, assume it is a file */
  442. if (statbuf.st_type == VDIR)
  443. return 0;
  444. return -1;
  445. }
  446. /*
  447. * Check whether AHAFS is mounted.
  448. * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
  449. */
  450. static int uv__is_ahafs_mounted(void){
  451. int rv, i = 2;
  452. struct vmount *p;
  453. int size_multiplier = 10;
  454. size_t siz = sizeof(struct vmount)*size_multiplier;
  455. struct vmount *vmt;
  456. const char *dev = "/aha";
  457. char *obj, *stub;
  458. p = malloc(siz);
  459. if (p == NULL)
  460. return -errno;
  461. /* Retrieve all mounted filesystems */
  462. rv = mntctl(MCTL_QUERY, siz, (char*)p);
  463. if (rv < 0)
  464. return -errno;
  465. if (rv == 0) {
  466. /* buffer was not large enough, reallocate to correct size */
  467. siz = *(int*)p;
  468. free(p);
  469. p = malloc(siz);
  470. if (p == NULL)
  471. return -errno;
  472. rv = mntctl(MCTL_QUERY, siz, (char*)p);
  473. if (rv < 0)
  474. return -errno;
  475. }
  476. /* Look for dev in filesystems mount info */
  477. for(vmt = p, i = 0; i < rv; i++) {
  478. obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
  479. stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
  480. if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
  481. free(p); /* Found a match */
  482. return 0;
  483. }
  484. vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
  485. }
  486. /* /aha is required for monitoring filesystem changes */
  487. return -1;
  488. }
  489. /*
  490. * Recursive call to mkdir() to create intermediate folders, if any
  491. * Returns code from mkdir call
  492. */
  493. static int uv__makedir_p(const char *dir) {
  494. char tmp[256];
  495. char *p = NULL;
  496. size_t len;
  497. int err;
  498. snprintf(tmp, sizeof(tmp),"%s",dir);
  499. len = strlen(tmp);
  500. if (tmp[len - 1] == '/')
  501. tmp[len - 1] = 0;
  502. for (p = tmp + 1; *p; p++) {
  503. if (*p == '/') {
  504. *p = 0;
  505. err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  506. if(err != 0)
  507. return err;
  508. *p = '/';
  509. }
  510. }
  511. return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  512. }
  513. /*
  514. * Creates necessary subdirectories in the AIX Event Infrastructure
  515. * file system for monitoring the object specified.
  516. * Returns code from mkdir call
  517. */
  518. static int uv__make_subdirs_p(const char *filename) {
  519. char cmd[2048];
  520. char *p;
  521. int rc = 0;
  522. /* Strip off the monitor file name */
  523. p = strrchr(filename, '/');
  524. if (p == NULL)
  525. return 0;
  526. if (uv__path_is_a_directory((char*)filename) == 0) {
  527. sprintf(cmd, "/aha/fs/modDir.monFactory");
  528. } else {
  529. sprintf(cmd, "/aha/fs/modFile.monFactory");
  530. }
  531. strncat(cmd, filename, (p - filename));
  532. rc = uv__makedir_p(cmd);
  533. if (rc == -1 && errno != EEXIST){
  534. return -errno;
  535. }
  536. return rc;
  537. }
  538. /*
  539. * Checks if /aha is mounted, then proceeds to set up the monitoring
  540. * objects for the specified file.
  541. * Returns 0 on success, or an error code < 0 on failure
  542. */
  543. static int uv__setup_ahafs(const char* filename, int *fd) {
  544. int rc = 0;
  545. char mon_file_write_string[RDWR_BUF_SIZE];
  546. char mon_file[PATH_MAX];
  547. int file_is_directory = 0; /* -1 == NO, 0 == YES */
  548. /* Create monitor file name for object */
  549. file_is_directory = uv__path_is_a_directory((char*)filename);
  550. if (file_is_directory == 0)
  551. sprintf(mon_file, "/aha/fs/modDir.monFactory");
  552. else
  553. sprintf(mon_file, "/aha/fs/modFile.monFactory");
  554. if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
  555. return -ENAMETOOLONG;
  556. /* Make the necessary subdirectories for the monitor file */
  557. rc = uv__make_subdirs_p(filename);
  558. if (rc == -1 && errno != EEXIST)
  559. return rc;
  560. strcat(mon_file, filename);
  561. strcat(mon_file, ".mon");
  562. *fd = 0; errno = 0;
  563. /* Open the monitor file, creating it if necessary */
  564. *fd = open(mon_file, O_CREAT|O_RDWR);
  565. if (*fd < 0)
  566. return -errno;
  567. /* Write out the monitoring specifications.
  568. * In this case, we are monitoring for a state change event type
  569. * CHANGED=YES
  570. * We will be waiting in select call, rather than a read:
  571. * WAIT_TYPE=WAIT_IN_SELECT
  572. * We only want minimal information for files:
  573. * INFO_LVL=1
  574. * For directories, we want more information to track what file
  575. * caused the change
  576. * INFO_LVL=2
  577. */
  578. if (file_is_directory == 0)
  579. sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
  580. else
  581. sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
  582. rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
  583. if (rc < 0)
  584. return -errno;
  585. return 0;
  586. }
  587. /*
  588. * Skips a specified number of lines in the buffer passed in.
  589. * Walks the buffer pointed to by p and attempts to skip n lines.
  590. * Returns the total number of lines skipped
  591. */
  592. static int uv__skip_lines(char **p, int n) {
  593. int lines = 0;
  594. while(n > 0) {
  595. *p = strchr(*p, '\n');
  596. if (!p)
  597. return lines;
  598. (*p)++;
  599. n--;
  600. lines++;
  601. }
  602. return lines;
  603. }
  604. /*
  605. * Parse the event occurrence data to figure out what event just occurred
  606. * and take proper action.
  607. *
  608. * The buf is a pointer to the buffer containing the event occurrence data
  609. * Returns 0 on success, -1 if unrecoverable error in parsing
  610. *
  611. */
  612. static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
  613. int evp_rc, i;
  614. char *p;
  615. char filename[PATH_MAX]; /* To be used when handling directories */
  616. p = buf;
  617. *events = 0;
  618. /* Clean the filename buffer*/
  619. for(i = 0; i < PATH_MAX; i++) {
  620. filename[i] = 0;
  621. }
  622. i = 0;
  623. /* Check for BUF_WRAP */
  624. if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
  625. assert(0 && "Buffer wrap detected, Some event occurrences lost!");
  626. return 0;
  627. }
  628. /* Since we are using the default buffer size (4K), and have specified
  629. * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications
  630. * should check for this keyword if they are using an INFO_LVL of 2 or
  631. * higher, and have a buffer size of <= 4K
  632. */
  633. /* Skip to RC_FROM_EVPROD */
  634. if (uv__skip_lines(&p, 9) != 9)
  635. return -1;
  636. if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
  637. if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
  638. if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
  639. /* The directory is no longer available for monitoring */
  640. *events = UV_RENAME;
  641. handle->dir_filename = NULL;
  642. } else {
  643. /* A file was added/removed inside the directory */
  644. *events = UV_CHANGE;
  645. /* Get the EVPROD_INFO */
  646. if (uv__skip_lines(&p, 1) != 1)
  647. return -1;
  648. /* Scan out the name of the file that triggered the event*/
  649. if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
  650. handle->dir_filename = strdup((const char*)&filename);
  651. } else
  652. return -1;
  653. }
  654. } else { /* Regular File */
  655. if (evp_rc == AHAFS_MODFILE_RENAME)
  656. *events = UV_RENAME;
  657. else
  658. *events = UV_CHANGE;
  659. }
  660. }
  661. else
  662. return -1;
  663. return 0;
  664. }
  665. /* This is the internal callback */
  666. static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
  667. char result_data[RDWR_BUF_SIZE];
  668. int bytes, rc = 0;
  669. uv_fs_event_t* handle;
  670. int events = 0;
  671. int i = 0;
  672. char fname[PATH_MAX];
  673. char *p;
  674. handle = container_of(event_watch, uv_fs_event_t, event_watcher);
  675. /* Clean all the buffers*/
  676. for(i = 0; i < PATH_MAX; i++) {
  677. fname[i] = 0;
  678. }
  679. i = 0;
  680. /* At this point, we assume that polling has been done on the
  681. * file descriptor, so we can just read the AHAFS event occurrence
  682. * data and parse its results without having to block anything
  683. */
  684. bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
  685. assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file");
  686. /* Parse the data */
  687. if(bytes > 0)
  688. rc = uv__parse_data(result_data, &events, handle);
  689. /* For directory changes, the name of the files that triggered the change
  690. * are never absolute pathnames
  691. */
  692. if (uv__path_is_a_directory(handle->path) == 0) {
  693. p = handle->dir_filename;
  694. while(*p != NULL){
  695. fname[i]= *p;
  696. i++;
  697. p++;
  698. }
  699. } else {
  700. /* For file changes, figure out whether filename is absolute or not */
  701. if (handle->path[0] == '/') {
  702. p = strrchr(handle->path, '/');
  703. p++;
  704. while(*p != NULL) {
  705. fname[i]= *p;
  706. i++;
  707. p++;
  708. }
  709. }
  710. }
  711. /* Unrecoverable error */
  712. if (rc == -1)
  713. return;
  714. else /* Call the actual JavaScript callback function */
  715. handle->cb(handle, (const char*)&fname, events, 0);
  716. }
  717. int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
  718. uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
  719. return 0;
  720. }
  721. int uv_fs_event_start(uv_fs_event_t* handle,
  722. uv_fs_event_cb cb,
  723. const char* filename,
  724. unsigned int flags) {
  725. int fd, rc, i = 0, res = 0;
  726. char cwd[PATH_MAX];
  727. char absolute_path[PATH_MAX];
  728. char fname[PATH_MAX];
  729. char *p;
  730. /* Clean all the buffers*/
  731. for(i = 0; i < PATH_MAX; i++) {
  732. cwd[i] = 0;
  733. absolute_path[i] = 0;
  734. fname[i] = 0;
  735. }
  736. i = 0;
  737. /* Figure out whether filename is absolute or not */
  738. if (filename[0] == '/') {
  739. /* We have absolute pathname, create the relative pathname*/
  740. sprintf(absolute_path, filename);
  741. p = strrchr(filename, '/');
  742. p++;
  743. } else {
  744. if (filename[0] == '.' && filename[1] == '/') {
  745. /* We have a relative pathname, compose the absolute pathname */
  746. sprintf(fname, filename);
  747. snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
  748. res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
  749. if (res < 0)
  750. return res;
  751. p = strrchr(absolute_path, '/');
  752. p++;
  753. p++;
  754. } else {
  755. /* We have a relative pathname, compose the absolute pathname */
  756. sprintf(fname, filename);
  757. snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
  758. res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
  759. if (res < 0)
  760. return res;
  761. p = strrchr(absolute_path, '/');
  762. p++;
  763. }
  764. /* Copy to filename buffer */
  765. while(filename[i] != NULL) {
  766. *p = filename[i];
  767. i++;
  768. p++;
  769. }
  770. }
  771. if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */
  772. return UV_ENOSYS;
  773. /* Setup ahafs */
  774. rc = uv__setup_ahafs((const char *)absolute_path, &fd);
  775. if (rc != 0)
  776. return rc;
  777. /* Setup/Initialize all the libuv routines */
  778. uv__handle_start(handle);
  779. uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
  780. handle->path = strdup((const char*)&absolute_path);
  781. handle->cb = cb;
  782. uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
  783. return 0;
  784. }
  785. int uv_fs_event_stop(uv_fs_event_t* handle) {
  786. if (!uv__is_active(handle))
  787. return 0;
  788. uv__io_close(handle->loop, &handle->event_watcher);
  789. uv__handle_stop(handle);
  790. if (uv__path_is_a_directory(handle->path) == 0) {
  791. free(handle->dir_filename);
  792. handle->dir_filename = NULL;
  793. }
  794. free(handle->path);
  795. handle->path = NULL;
  796. uv__close(handle->event_watcher.fd);
  797. handle->event_watcher.fd = -1;
  798. return 0;
  799. }
  800. void uv__fs_event_close(uv_fs_event_t* handle) {
  801. uv_fs_event_stop(handle);
  802. }
  803. char** uv_setup_args(int argc, char** argv) {
  804. return argv;
  805. }
  806. int uv_set_process_title(const char* title) {
  807. return 0;
  808. }
  809. int uv_get_process_title(char* buffer, size_t size) {
  810. if (size > 0) {
  811. buffer[0] = '\0';
  812. }
  813. return 0;
  814. }
  815. int uv_resident_set_memory(size_t* rss) {
  816. char pp[64];
  817. psinfo_t psinfo;
  818. int err;
  819. int fd;
  820. snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
  821. fd = open(pp, O_RDONLY);
  822. if (fd == -1)
  823. return -errno;
  824. /* FIXME(bnoordhuis) Handle EINTR. */
  825. err = -EINVAL;
  826. if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
  827. *rss = (size_t)psinfo.pr_rssize * 1024;
  828. err = 0;
  829. }
  830. uv__close(fd);
  831. return err;
  832. }
  833. int uv_uptime(double* uptime) {
  834. struct utmp *utmp_buf;
  835. size_t entries = 0;
  836. time_t boot_time;
  837. utmpname(UTMP_FILE);
  838. setutent();
  839. while ((utmp_buf = getutent()) != NULL) {
  840. if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
  841. ++entries;
  842. if (utmp_buf->ut_type == BOOT_TIME)
  843. boot_time = utmp_buf->ut_time;
  844. }
  845. endutent();
  846. if (boot_time == 0)
  847. return -ENOSYS;
  848. *uptime = time(NULL) - boot_time;
  849. return 0;
  850. }
  851. int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
  852. uv_cpu_info_t* cpu_info;
  853. perfstat_cpu_total_t ps_total;
  854. perfstat_cpu_t* ps_cpus;
  855. perfstat_id_t cpu_id;
  856. int result, ncpus, idx = 0;
  857. result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
  858. if (result == -1) {
  859. return -ENOSYS;
  860. }
  861. ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
  862. if (result == -1) {
  863. return -ENOSYS;
  864. }
  865. ps_cpus = (perfstat_cpu_t*) malloc(ncpus * sizeof(perfstat_cpu_t));
  866. if (!ps_cpus) {
  867. return -ENOMEM;
  868. }
  869. strcpy(cpu_id.name, FIRST_CPU);
  870. result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
  871. if (result == -1) {
  872. free(ps_cpus);
  873. return -ENOSYS;
  874. }
  875. *cpu_infos = (uv_cpu_info_t*) malloc(ncpus * sizeof(uv_cpu_info_t));
  876. if (!*cpu_infos) {
  877. free(ps_cpus);
  878. return -ENOMEM;
  879. }
  880. *count = ncpus;
  881. cpu_info = *cpu_infos;
  882. while (idx < ncpus) {
  883. cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
  884. cpu_info->model = strdup(ps_total.description);
  885. cpu_info->cpu_times.user = ps_cpus[idx].user;
  886. cpu_info->cpu_times.sys = ps_cpus[idx].sys;
  887. cpu_info->cpu_times.idle = ps_cpus[idx].idle;
  888. cpu_info->cpu_times.irq = ps_cpus[idx].wait;
  889. cpu_info->cpu_times.nice = 0;
  890. cpu_info++;
  891. idx++;
  892. }
  893. free(ps_cpus);
  894. return 0;
  895. }
  896. void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
  897. int i;
  898. for (i = 0; i < count; ++i) {
  899. free(cpu_infos[i].model);
  900. }
  901. free(cpu_infos);
  902. }
  903. int uv_interface_addresses(uv_interface_address_t** addresses,
  904. int* count) {
  905. uv_interface_address_t* address;
  906. int sockfd, size = 1;
  907. struct ifconf ifc;
  908. struct ifreq *ifr, *p, flg;
  909. *count = 0;
  910. if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
  911. return -errno;
  912. }
  913. if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
  914. SAVE_ERRNO(uv__close(sockfd));
  915. return -errno;
  916. }
  917. ifc.ifc_req = (struct ifreq*)malloc(size);
  918. ifc.ifc_len = size;
  919. if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
  920. SAVE_ERRNO(uv__close(sockfd));
  921. return -errno;
  922. }
  923. #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
  924. /* Count all up and running ipv4/ipv6 addresses */
  925. ifr = ifc.ifc_req;
  926. while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
  927. p = ifr;
  928. ifr = (struct ifreq*)
  929. ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
  930. if (!(p->ifr_addr.sa_family == AF_INET6 ||
  931. p->ifr_addr.sa_family == AF_INET))
  932. continue;
  933. memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
  934. if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
  935. SAVE_ERRNO(uv__close(sockfd));
  936. return -errno;
  937. }
  938. if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
  939. continue;
  940. (*count)++;
  941. }
  942. /* Alloc the return interface structs */
  943. *addresses = (uv_interface_address_t*)
  944. malloc(*count * sizeof(uv_interface_address_t));
  945. if (!(*addresses)) {
  946. uv__close(sockfd);
  947. return -ENOMEM;
  948. }
  949. address = *addresses;
  950. ifr = ifc.ifc_req;
  951. while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
  952. p = ifr;
  953. ifr = (struct ifreq*)
  954. ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
  955. if (!(p->ifr_addr.sa_family == AF_INET6 ||
  956. p->ifr_addr.sa_family == AF_INET))
  957. continue;
  958. memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
  959. if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
  960. uv__close(sockfd);
  961. return -ENOSYS;
  962. }
  963. if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
  964. continue;
  965. /* All conditions above must match count loop */
  966. address->name = strdup(p->ifr_name);
  967. if (p->ifr_addr.sa_family == AF_INET6) {
  968. address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
  969. } else {
  970. address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
  971. }
  972. /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
  973. address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
  974. address++;
  975. }
  976. #undef ADDR_SIZE
  977. uv__close(sockfd);
  978. return 0;
  979. }
  980. void uv_free_interface_addresses(uv_interface_address_t* addresses,
  981. int count) {
  982. int i;
  983. for (i = 0; i < count; ++i) {
  984. free(addresses[i].name);
  985. }
  986. free(addresses);
  987. }
  988. void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
  989. struct pollfd* events;
  990. uintptr_t i;
  991. uintptr_t nfds;
  992. struct poll_ctl pc;
  993. assert(loop->watchers != NULL);
  994. events = (struct pollfd*) loop->watchers[loop->nwatchers];
  995. nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
  996. if (events != NULL)
  997. /* Invalidate events with same file descriptor */
  998. for (i = 0; i < nfds; i++)
  999. if ((int) events[i].fd == fd)
  1000. events[i].fd = -1;
  1001. /* Remove the file descriptor from the poll set */
  1002. pc.events = 0;
  1003. pc.cmd = PS_DELETE;
  1004. pc.fd = fd;
  1005. if(loop->backend_fd >= 0)
  1006. pollset_ctl(loop->backend_fd, &pc, 1);
  1007. }