Blame src/unix/core.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
Packit b5b901
#include <stddef.h> /* NULL */
Packit b5b901
#include <stdio.h> /* printf */
Packit b5b901
#include <stdlib.h>
Packit b5b901
#include <string.h> /* strerror */
Packit b5b901
#include <errno.h>
Packit b5b901
#include <assert.h>
Packit b5b901
#include <unistd.h>
Packit b5b901
#include <sys/types.h>
Packit b5b901
#include <sys/stat.h>
Packit Service e08953
#include <fcntl.h>  /* O_CLOEXEC */
Packit b5b901
#include <sys/ioctl.h>
Packit b5b901
#include <sys/socket.h>
Packit b5b901
#include <sys/un.h>
Packit b5b901
#include <netinet/in.h>
Packit b5b901
#include <arpa/inet.h>
Packit b5b901
#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
Packit b5b901
#include <sys/uio.h> /* writev */
Packit b5b901
#include <sys/resource.h> /* getrusage */
Packit b5b901
#include <pwd.h>
Packit Service e08953
#include <sys/utsname.h>
Packit Service e08953
#include <sys/time.h>
Packit b5b901
Packit b5b901
#ifdef __sun
Packit b5b901
# include <sys/filio.h>
Packit b5b901
# include <sys/types.h>
Packit b5b901
# include <sys/wait.h>
Packit b5b901
#endif
Packit b5b901
Packit Service e08953
#if defined(__APPLE__)
Packit b5b901
# include <sys/filio.h>
Packit Service e08953
# endif /* defined(__APPLE__) */
Packit Service e08953
Packit Service e08953
Packit Service e08953
#if defined(__APPLE__) && !TARGET_OS_IPHONE
Packit Service e08953
# include <crt_externs.h>
Packit Service e08953
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
Packit Service e08953
# define environ (*_NSGetEnviron())
Packit Service e08953
#else /* defined(__APPLE__) && !TARGET_OS_IPHONE */
Packit Service e08953
extern char** environ;
Packit Service e08953
#endif /* !(defined(__APPLE__) && !TARGET_OS_IPHONE) */
Packit Service e08953
Packit b5b901
Packit b5b901
#if defined(__DragonFly__)      || \
Packit b5b901
    defined(__FreeBSD__)        || \
Packit b5b901
    defined(__FreeBSD_kernel__) || \
Packit Service e08953
    defined(__NetBSD__)         || \
Packit Service e08953
    defined(__OpenBSD__)
Packit b5b901
# include <sys/sysctl.h>
Packit b5b901
# include <sys/filio.h>
Packit b5b901
# include <sys/wait.h>
Packit Service e08953
# if defined(__FreeBSD__)
Packit b5b901
#  define uv__accept4 accept4
Packit b5b901
# endif
Packit b5b901
# if defined(__NetBSD__)
Packit b5b901
#  define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
Packit b5b901
# endif
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
Packit b5b901
# include <dlfcn.h>  /* for dlsym */
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#if defined(__MVS__)
Packit b5b901
#include <sys/ioctl.h>
Packit b5b901
#endif
Packit b5b901
Packit Service e08953
#if defined(__linux__)
Packit Service e08953
# include <sys/syscall.h>
Packit Service e08953
# define uv__accept4 accept4
Packit b5b901
#endif
Packit b5b901
Packit b5b901
static int uv__run_pending(uv_loop_t* loop);
Packit b5b901
Packit b5b901
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
Packit b5b901
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
Packit b5b901
STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
Packit b5b901
              sizeof(((struct iovec*) 0)->iov_base));
Packit b5b901
STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
Packit b5b901
              sizeof(((struct iovec*) 0)->iov_len));
Packit b5b901
STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
Packit b5b901
STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv_hrtime(void) {
Packit b5b901
  return uv__hrtime(UV_CLOCK_PRECISE);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
Packit b5b901
  assert(!uv__is_closing(handle));
Packit b5b901
Packit b5b901
  handle->flags |= UV_HANDLE_CLOSING;
Packit b5b901
  handle->close_cb = close_cb;
Packit b5b901
Packit b5b901
  switch (handle->type) {
Packit b5b901
  case UV_NAMED_PIPE:
Packit b5b901
    uv__pipe_close((uv_pipe_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_TTY:
Packit b5b901
    uv__stream_close((uv_stream_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_TCP:
Packit b5b901
    uv__tcp_close((uv_tcp_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_UDP:
Packit b5b901
    uv__udp_close((uv_udp_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_PREPARE:
Packit b5b901
    uv__prepare_close((uv_prepare_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_CHECK:
Packit b5b901
    uv__check_close((uv_check_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_IDLE:
Packit b5b901
    uv__idle_close((uv_idle_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_ASYNC:
Packit b5b901
    uv__async_close((uv_async_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_TIMER:
Packit b5b901
    uv__timer_close((uv_timer_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_PROCESS:
Packit b5b901
    uv__process_close((uv_process_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_FS_EVENT:
Packit b5b901
    uv__fs_event_close((uv_fs_event_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_POLL:
Packit b5b901
    uv__poll_close((uv_poll_t*)handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_FS_POLL:
Packit b5b901
    uv__fs_poll_close((uv_fs_poll_t*)handle);
Packit Service e08953
    /* Poll handles use file system requests, and one of them may still be
Packit Service e08953
     * running. The poll code will call uv__make_close_pending() for us. */
Packit Service e08953
    return;
Packit b5b901
Packit b5b901
  case UV_SIGNAL:
Packit b5b901
    uv__signal_close((uv_signal_t*) handle);
Packit Service e08953
    break;
Packit b5b901
Packit b5b901
  default:
Packit b5b901
    assert(0);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__make_close_pending(handle);
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
Packit b5b901
  int r;
Packit b5b901
  int fd;
Packit b5b901
  socklen_t len;
Packit b5b901
Packit b5b901
  if (handle == NULL || value == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
Packit b5b901
    fd = uv__stream_fd((uv_stream_t*) handle);
Packit b5b901
  else if (handle->type == UV_UDP)
Packit b5b901
    fd = ((uv_udp_t *) handle)->io_watcher.fd;
Packit b5b901
  else
Packit b5b901
    return UV_ENOTSUP;
Packit b5b901
Packit b5b901
  len = sizeof(*value);
Packit b5b901
Packit b5b901
  if (*value == 0)
Packit b5b901
    r = getsockopt(fd, SOL_SOCKET, optname, value, &len;;
Packit b5b901
  else
Packit b5b901
    r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
Packit b5b901
Packit b5b901
  if (r < 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
void uv__make_close_pending(uv_handle_t* handle) {
Packit b5b901
  assert(handle->flags & UV_HANDLE_CLOSING);
Packit b5b901
  assert(!(handle->flags & UV_HANDLE_CLOSED));
Packit b5b901
  handle->next_closing = handle->loop->closing_handles;
Packit b5b901
  handle->loop->closing_handles = handle;
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv__getiovmax(void) {
Packit b5b901
#if defined(IOV_MAX)
Packit b5b901
  return IOV_MAX;
Packit b5b901
#elif defined(_SC_IOV_MAX)
Packit b5b901
  static int iovmax = -1;
Packit b5b901
  if (iovmax == -1) {
Packit b5b901
    iovmax = sysconf(_SC_IOV_MAX);
Packit b5b901
    /* On some embedded devices (arm-linux-uclibc based ip camera),
Packit b5b901
     * sysconf(_SC_IOV_MAX) can not get the correct value. The return
Packit b5b901
     * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
Packit b5b901
     */
Packit b5b901
    if (iovmax == -1) iovmax = 1;
Packit b5b901
  }
Packit b5b901
  return iovmax;
Packit b5b901
#else
Packit b5b901
  return 1024;
Packit b5b901
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv__finish_close(uv_handle_t* handle) {
Packit Service e08953
  uv_signal_t* sh;
Packit Service e08953
Packit b5b901
  /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
Packit b5b901
   * possible for it to be active in the sense that uv__is_active() returns
Packit b5b901
   * true.
Packit b5b901
   *
Packit b5b901
   * A good example is when the user calls uv_shutdown(), immediately followed
Packit b5b901
   * by uv_close(). The handle is considered active at this point because the
Packit b5b901
   * completion of the shutdown req is still pending.
Packit b5b901
   */
Packit b5b901
  assert(handle->flags & UV_HANDLE_CLOSING);
Packit b5b901
  assert(!(handle->flags & UV_HANDLE_CLOSED));
Packit b5b901
  handle->flags |= UV_HANDLE_CLOSED;
Packit b5b901
Packit b5b901
  switch (handle->type) {
Packit b5b901
    case UV_PREPARE:
Packit b5b901
    case UV_CHECK:
Packit b5b901
    case UV_IDLE:
Packit b5b901
    case UV_ASYNC:
Packit b5b901
    case UV_TIMER:
Packit b5b901
    case UV_PROCESS:
Packit b5b901
    case UV_FS_EVENT:
Packit b5b901
    case UV_FS_POLL:
Packit b5b901
    case UV_POLL:
Packit Service e08953
      break;
Packit Service e08953
Packit b5b901
    case UV_SIGNAL:
Packit Service e08953
      /* If there are any caught signals "trapped" in the signal pipe,
Packit Service e08953
       * we can't call the close callback yet. Reinserting the handle
Packit Service e08953
       * into the closing queue makes the event loop spin but that's
Packit Service e08953
       * okay because we only need to deliver the pending events.
Packit Service e08953
       */
Packit Service e08953
      sh = (uv_signal_t*) handle;
Packit Service e08953
      if (sh->caught_signals > sh->dispatched_signals) {
Packit Service e08953
        handle->flags ^= UV_HANDLE_CLOSED;
Packit Service e08953
        uv__make_close_pending(handle);  /* Back into the queue. */
Packit Service e08953
        return;
Packit Service e08953
      }
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case UV_NAMED_PIPE:
Packit b5b901
    case UV_TCP:
Packit b5b901
    case UV_TTY:
Packit b5b901
      uv__stream_destroy((uv_stream_t*)handle);
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case UV_UDP:
Packit b5b901
      uv__udp_finish_close((uv_udp_t*)handle);
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    default:
Packit b5b901
      assert(0);
Packit b5b901
      break;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__handle_unref(handle);
Packit b5b901
  QUEUE_REMOVE(&handle->handle_queue);
Packit b5b901
Packit b5b901
  if (handle->close_cb) {
Packit b5b901
    handle->close_cb(handle);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv__run_closing_handles(uv_loop_t* loop) {
Packit b5b901
  uv_handle_t* p;
Packit b5b901
  uv_handle_t* q;
Packit b5b901
Packit b5b901
  p = loop->closing_handles;
Packit b5b901
  loop->closing_handles = NULL;
Packit b5b901
Packit b5b901
  while (p) {
Packit b5b901
    q = p->next_closing;
Packit b5b901
    uv__finish_close(p);
Packit b5b901
    p = q;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_is_closing(const uv_handle_t* handle) {
Packit b5b901
  return uv__is_closing(handle);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_backend_fd(const uv_loop_t* loop) {
Packit b5b901
  return loop->backend_fd;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_backend_timeout(const uv_loop_t* loop) {
Packit b5b901
  if (loop->stop_flag != 0)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (!QUEUE_EMPTY(&loop->idle_handles))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (!QUEUE_EMPTY(&loop->pending_queue))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (loop->closing_handles)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  return uv__next_timeout(loop);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv__loop_alive(const uv_loop_t* loop) {
Packit b5b901
  return uv__has_active_handles(loop) ||
Packit b5b901
         uv__has_active_reqs(loop) ||
Packit b5b901
         loop->closing_handles != NULL;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_loop_alive(const uv_loop_t* loop) {
Packit b5b901
    return uv__loop_alive(loop);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
Packit b5b901
  int timeout;
Packit b5b901
  int r;
Packit b5b901
  int ran_pending;
Packit b5b901
Packit b5b901
  r = uv__loop_alive(loop);
Packit b5b901
  if (!r)
Packit b5b901
    uv__update_time(loop);
Packit b5b901
Packit b5b901
  while (r != 0 && loop->stop_flag == 0) {
Packit b5b901
    uv__update_time(loop);
Packit b5b901
    uv__run_timers(loop);
Packit b5b901
    ran_pending = uv__run_pending(loop);
Packit b5b901
    uv__run_idle(loop);
Packit b5b901
    uv__run_prepare(loop);
Packit b5b901
Packit b5b901
    timeout = 0;
Packit b5b901
    if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
Packit b5b901
      timeout = uv_backend_timeout(loop);
Packit b5b901
Packit b5b901
    uv__io_poll(loop, timeout);
Packit b5b901
    uv__run_check(loop);
Packit b5b901
    uv__run_closing_handles(loop);
Packit b5b901
Packit b5b901
    if (mode == UV_RUN_ONCE) {
Packit b5b901
      /* UV_RUN_ONCE implies forward progress: at least one callback must have
Packit b5b901
       * been invoked when it returns. uv__io_poll() can return without doing
Packit b5b901
       * I/O (meaning: no callbacks) when its timeout expires - which means we
Packit b5b901
       * have pending timers that satisfy the forward progress constraint.
Packit b5b901
       *
Packit b5b901
       * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
Packit b5b901
       * the check.
Packit b5b901
       */
Packit b5b901
      uv__update_time(loop);
Packit b5b901
      uv__run_timers(loop);
Packit b5b901
    }
Packit b5b901
Packit b5b901
    r = uv__loop_alive(loop);
Packit b5b901
    if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
Packit b5b901
      break;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* The if statement lets gcc compile it to a conditional store. Avoids
Packit b5b901
   * dirtying a cache line.
Packit b5b901
   */
Packit b5b901
  if (loop->stop_flag != 0)
Packit b5b901
    loop->stop_flag = 0;
Packit b5b901
Packit b5b901
  return r;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_update_time(uv_loop_t* loop) {
Packit b5b901
  uv__update_time(loop);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_is_active(const uv_handle_t* handle) {
Packit b5b901
  return uv__is_active(handle);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
Packit b5b901
int uv__socket(int domain, int type, int protocol) {
Packit b5b901
  int sockfd;
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
Packit b5b901
  sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
Packit b5b901
  if (sockfd != -1)
Packit b5b901
    return sockfd;
Packit b5b901
Packit b5b901
  if (errno != EINVAL)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  sockfd = socket(domain, type, protocol);
Packit b5b901
  if (sockfd == -1)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  err = uv__nonblock(sockfd, 1);
Packit b5b901
  if (err == 0)
Packit b5b901
    err = uv__cloexec(sockfd, 1);
Packit b5b901
Packit b5b901
  if (err) {
Packit b5b901
    uv__close(sockfd);
Packit b5b901
    return err;
Packit b5b901
  }
Packit b5b901
Packit b5b901
#if defined(SO_NOSIGPIPE)
Packit b5b901
  {
Packit b5b901
    int on = 1;
Packit b5b901
    setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
Packit b5b901
  }
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  return sockfd;
Packit b5b901
}
Packit b5b901
Packit b5b901
/* get a file pointer to a file in read-only and close-on-exec mode */
Packit b5b901
FILE* uv__open_file(const char* path) {
Packit b5b901
  int fd;
Packit b5b901
  FILE* fp;
Packit b5b901
Packit b5b901
  fd = uv__open_cloexec(path, O_RDONLY);
Packit b5b901
  if (fd < 0)
Packit b5b901
    return NULL;
Packit b5b901
Packit b5b901
   fp = fdopen(fd, "r");
Packit b5b901
   if (fp == NULL)
Packit b5b901
     uv__close(fd);
Packit b5b901
Packit b5b901
   return fp;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__accept(int sockfd) {
Packit b5b901
  int peerfd;
Packit b5b901
  int err;
Packit b5b901
Packit Service e08953
  (void) &err;
Packit b5b901
  assert(sockfd >= 0);
Packit b5b901
Packit Service e08953
  do
Packit Service e08953
#ifdef uv__accept4
Packit Service e08953
    peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
Packit Service e08953
#else
Packit Service e08953
    peerfd = accept(sockfd, NULL, NULL);
Packit Service e08953
#endif
Packit Service e08953
  while (peerfd == -1 && errno == EINTR);
Packit b5b901
Packit Service e08953
  if (peerfd == -1)
Packit Service e08953
    return UV__ERR(errno);
Packit b5b901
Packit Service e08953
#ifndef uv__accept4
Packit Service e08953
  err = uv__cloexec(peerfd, 1);
Packit Service e08953
  if (err == 0)
Packit Service e08953
    err = uv__nonblock(peerfd, 1);
Packit b5b901
Packit Service e08953
  if (err != 0) {
Packit Service e08953
    uv__close(peerfd);
Packit Service e08953
    return err;
Packit Service e08953
  }
Packit b5b901
#endif
Packit b5b901
Packit Service e08953
  return peerfd;
Packit Service e08953
}
Packit b5b901
Packit b5b901
Packit Service e08953
/* close() on macos has the "interesting" quirk that it fails with EINTR
Packit Service e08953
 * without closing the file descriptor when a thread is in the cancel state.
Packit Service e08953
 * That's why libuv calls close$NOCANCEL() instead.
Packit Service e08953
 *
Packit Service e08953
 * glibc on linux has a similar issue: close() is a cancellation point and
Packit Service e08953
 * will unwind the thread when it's in the cancel state. Work around that
Packit Service e08953
 * by making the system call directly. Musl libc is unaffected.
Packit Service e08953
 */
Packit Service e08953
int uv__close_nocancel(int fd) {
Packit Service e08953
#if defined(__APPLE__)
Packit Service e08953
#pragma GCC diagnostic push
Packit Service e08953
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
Packit Service e08953
#if defined(__LP64__) || TARGET_OS_IPHONE
Packit Service e08953
  extern int close$NOCANCEL(int);
Packit Service e08953
  return close$NOCANCEL(fd);
Packit Service e08953
#else
Packit Service e08953
  extern int close$NOCANCEL$UNIX2003(int);
Packit Service e08953
  return close$NOCANCEL$UNIX2003(fd);
Packit Service e08953
#endif
Packit Service e08953
#pragma GCC diagnostic pop
Packit Service e08953
#elif defined(__linux__)
Packit Service e08953
  return syscall(SYS_close, fd);
Packit Service e08953
#else
Packit Service e08953
  return close(fd);
Packit Service e08953
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__close_nocheckstdio(int fd) {
Packit b5b901
  int saved_errno;
Packit b5b901
  int rc;
Packit b5b901
Packit b5b901
  assert(fd > -1);  /* Catch uninitialized io_watcher.fd bugs. */
Packit b5b901
Packit b5b901
  saved_errno = errno;
Packit Service e08953
  rc = uv__close_nocancel(fd);
Packit b5b901
  if (rc == -1) {
Packit b5b901
    rc = UV__ERR(errno);
Packit b5b901
    if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS))
Packit b5b901
      rc = 0;    /* The close is in progress, not an error. */
Packit b5b901
    errno = saved_errno;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return rc;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__close(int fd) {
Packit b5b901
  assert(fd > STDERR_FILENO);  /* Catch stdio close bugs. */
Packit b5b901
#if defined(__MVS__)
Packit b5b901
  SAVE_ERRNO(epoll_file_close(fd));
Packit b5b901
#endif
Packit b5b901
  return uv__close_nocheckstdio(fd);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__nonblock_ioctl(int fd, int set) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    r = ioctl(fd, FIONBIO, &set);
Packit b5b901
  while (r == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (r)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__)
Packit b5b901
int uv__cloexec_ioctl(int fd, int set) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
Packit b5b901
  while (r == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (r)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
int uv__nonblock_fcntl(int fd, int set) {
Packit b5b901
  int flags;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    r = fcntl(fd, F_GETFL);
Packit b5b901
  while (r == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (r == -1)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  /* Bail out now if already set/clear. */
Packit b5b901
  if (!!(r & O_NONBLOCK) == !!set)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (set)
Packit b5b901
    flags = r | O_NONBLOCK;
Packit b5b901
  else
Packit b5b901
    flags = r & ~O_NONBLOCK;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    r = fcntl(fd, F_SETFL, flags);
Packit b5b901
  while (r == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (r)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__cloexec_fcntl(int fd, int set) {
Packit b5b901
  int flags;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    r = fcntl(fd, F_GETFD);
Packit b5b901
  while (r == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (r == -1)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  /* Bail out now if already set/clear. */
Packit b5b901
  if (!!(r & FD_CLOEXEC) == !!set)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (set)
Packit b5b901
    flags = r | FD_CLOEXEC;
Packit b5b901
  else
Packit b5b901
    flags = r & ~FD_CLOEXEC;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    r = fcntl(fd, F_SETFD, flags);
Packit b5b901
  while (r == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (r)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
Packit b5b901
  struct cmsghdr* cmsg;
Packit b5b901
  ssize_t rc;
Packit b5b901
  int* pfd;
Packit b5b901
  int* end;
Packit b5b901
#if defined(__linux__)
Packit b5b901
  static int no_msg_cmsg_cloexec;
Packit b5b901
  if (no_msg_cmsg_cloexec == 0) {
Packit b5b901
    rc = recvmsg(fd, msg, flags | 0x40000000);  /* MSG_CMSG_CLOEXEC */
Packit b5b901
    if (rc != -1)
Packit b5b901
      return rc;
Packit b5b901
    if (errno != EINVAL)
Packit b5b901
      return UV__ERR(errno);
Packit b5b901
    rc = recvmsg(fd, msg, flags);
Packit b5b901
    if (rc == -1)
Packit b5b901
      return UV__ERR(errno);
Packit b5b901
    no_msg_cmsg_cloexec = 1;
Packit b5b901
  } else {
Packit b5b901
    rc = recvmsg(fd, msg, flags);
Packit b5b901
  }
Packit b5b901
#else
Packit b5b901
  rc = recvmsg(fd, msg, flags);
Packit b5b901
#endif
Packit b5b901
  if (rc == -1)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
  if (msg->msg_controllen == 0)
Packit b5b901
    return rc;
Packit b5b901
  for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
Packit b5b901
    if (cmsg->cmsg_type == SCM_RIGHTS)
Packit b5b901
      for (pfd = (int*) CMSG_DATA(cmsg),
Packit b5b901
           end = (int*) ((char*) cmsg + cmsg->cmsg_len);
Packit b5b901
           pfd < end;
Packit b5b901
           pfd += 1)
Packit b5b901
        uv__cloexec(*pfd, 1);
Packit b5b901
  return rc;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_cwd(char* buffer, size_t* size) {
Packit Service e08953
  char scratch[1 + UV__PATH_MAX];
Packit Service e08953
Packit b5b901
  if (buffer == NULL || size == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit Service e08953
  /* Try to read directly into the user's buffer first... */
Packit Service e08953
  if (getcwd(buffer, *size) != NULL)
Packit Service e08953
    goto fixup;
Packit Service e08953
Packit Service e08953
  if (errno != ERANGE)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit Service e08953
  /* ...or into scratch space if the user's buffer is too small
Packit Service e08953
   * so we can report how much space to provide on the next try.
Packit Service e08953
   */
Packit Service e08953
  if (getcwd(scratch, sizeof(scratch)) == NULL)
Packit Service e08953
    return UV__ERR(errno);
Packit Service e08953
Packit Service e08953
  buffer = scratch;
Packit Service e08953
Packit Service e08953
fixup:
Packit Service e08953
Packit b5b901
  *size = strlen(buffer);
Packit Service e08953
Packit b5b901
  if (*size > 1 && buffer[*size - 1] == '/') {
Packit Service e08953
    *size -= 1;
Packit Service e08953
    buffer[*size] = '\0';
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  if (buffer == scratch) {
Packit Service e08953
    *size += 1;
Packit Service e08953
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_chdir(const char* dir) {
Packit b5b901
  if (chdir(dir))
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_disable_stdio_inheritance(void) {
Packit b5b901
  int fd;
Packit b5b901
Packit b5b901
  /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the
Packit b5b901
   * first 16 file descriptors. After that, bail out after the first error.
Packit b5b901
   */
Packit b5b901
  for (fd = 0; ; fd++)
Packit b5b901
    if (uv__cloexec(fd, 1) && fd > 15)
Packit b5b901
      break;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
Packit b5b901
  int fd_out;
Packit b5b901
Packit b5b901
  switch (handle->type) {
Packit b5b901
  case UV_TCP:
Packit b5b901
  case UV_NAMED_PIPE:
Packit b5b901
  case UV_TTY:
Packit b5b901
    fd_out = uv__stream_fd((uv_stream_t*) handle);
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_UDP:
Packit b5b901
    fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  case UV_POLL:
Packit b5b901
    fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
Packit b5b901
    break;
Packit b5b901
Packit b5b901
  default:
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (uv__is_closing(handle) || fd_out == -1)
Packit b5b901
    return UV_EBADF;
Packit b5b901
Packit b5b901
  *fd = fd_out;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv__run_pending(uv_loop_t* loop) {
Packit b5b901
  QUEUE* q;
Packit b5b901
  QUEUE pq;
Packit b5b901
  uv__io_t* w;
Packit b5b901
Packit b5b901
  if (QUEUE_EMPTY(&loop->pending_queue))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  QUEUE_MOVE(&loop->pending_queue, &pq;;
Packit b5b901
Packit b5b901
  while (!QUEUE_EMPTY(&pq)) {
Packit b5b901
    q = QUEUE_HEAD(&pq;;
Packit b5b901
    QUEUE_REMOVE(q);
Packit b5b901
    QUEUE_INIT(q);
Packit b5b901
    w = QUEUE_DATA(q, uv__io_t, pending_queue);
Packit b5b901
    w->cb(loop, w, POLLOUT);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 1;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static unsigned int next_power_of_two(unsigned int val) {
Packit b5b901
  val -= 1;
Packit b5b901
  val |= val >> 1;
Packit b5b901
  val |= val >> 2;
Packit b5b901
  val |= val >> 4;
Packit b5b901
  val |= val >> 8;
Packit b5b901
  val |= val >> 16;
Packit b5b901
  val += 1;
Packit b5b901
  return val;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void maybe_resize(uv_loop_t* loop, unsigned int len) {
Packit b5b901
  uv__io_t** watchers;
Packit b5b901
  void* fake_watcher_list;
Packit b5b901
  void* fake_watcher_count;
Packit b5b901
  unsigned int nwatchers;
Packit b5b901
  unsigned int i;
Packit b5b901
Packit b5b901
  if (len <= loop->nwatchers)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  /* Preserve fake watcher list and count at the end of the watchers */
Packit b5b901
  if (loop->watchers != NULL) {
Packit b5b901
    fake_watcher_list = loop->watchers[loop->nwatchers];
Packit b5b901
    fake_watcher_count = loop->watchers[loop->nwatchers + 1];
Packit b5b901
  } else {
Packit b5b901
    fake_watcher_list = NULL;
Packit b5b901
    fake_watcher_count = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  nwatchers = next_power_of_two(len + 2) - 2;
Packit Service e08953
  watchers = uv__reallocf(loop->watchers,
Packit Service e08953
                          (nwatchers + 2) * sizeof(loop->watchers[0]));
Packit b5b901
Packit b5b901
  if (watchers == NULL)
Packit b5b901
    abort();
Packit b5b901
  for (i = loop->nwatchers; i < nwatchers; i++)
Packit b5b901
    watchers[i] = NULL;
Packit b5b901
  watchers[nwatchers] = fake_watcher_list;
Packit b5b901
  watchers[nwatchers + 1] = fake_watcher_count;
Packit b5b901
Packit b5b901
  loop->watchers = watchers;
Packit b5b901
  loop->nwatchers = nwatchers;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
Packit b5b901
  assert(cb != NULL);
Packit b5b901
  assert(fd >= -1);
Packit b5b901
  QUEUE_INIT(&w->pending_queue);
Packit b5b901
  QUEUE_INIT(&w->watcher_queue);
Packit b5b901
  w->cb = cb;
Packit b5b901
  w->fd = fd;
Packit b5b901
  w->events = 0;
Packit b5b901
  w->pevents = 0;
Packit b5b901
Packit b5b901
#if defined(UV_HAVE_KQUEUE)
Packit b5b901
  w->rcount = 0;
Packit b5b901
  w->wcount = 0;
Packit b5b901
#endif /* defined(UV_HAVE_KQUEUE) */
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
Packit b5b901
  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
Packit b5b901
  assert(0 != events);
Packit b5b901
  assert(w->fd >= 0);
Packit b5b901
  assert(w->fd < INT_MAX);
Packit b5b901
Packit b5b901
  w->pevents |= events;
Packit b5b901
  maybe_resize(loop, w->fd + 1);
Packit b5b901
Packit b5b901
#if !defined(__sun)
Packit b5b901
  /* The event ports backend needs to rearm all file descriptors on each and
Packit b5b901
   * every tick of the event loop but the other backends allow us to
Packit b5b901
   * short-circuit here if the event mask is unchanged.
Packit b5b901
   */
Packit b5b901
  if (w->events == w->pevents)
Packit b5b901
    return;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  if (QUEUE_EMPTY(&w->watcher_queue))
Packit b5b901
    QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
Packit b5b901
Packit b5b901
  if (loop->watchers[w->fd] == NULL) {
Packit b5b901
    loop->watchers[w->fd] = w;
Packit b5b901
    loop->nfds++;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
Packit b5b901
  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
Packit b5b901
  assert(0 != events);
Packit b5b901
Packit b5b901
  if (w->fd == -1)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  assert(w->fd >= 0);
Packit b5b901
Packit b5b901
  /* Happens when uv__io_stop() is called on a handle that was never started. */
Packit b5b901
  if ((unsigned) w->fd >= loop->nwatchers)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  w->pevents &= ~events;
Packit b5b901
Packit b5b901
  if (w->pevents == 0) {
Packit b5b901
    QUEUE_REMOVE(&w->watcher_queue);
Packit b5b901
    QUEUE_INIT(&w->watcher_queue);
Packit b5b901
Packit b5b901
    if (loop->watchers[w->fd] != NULL) {
Packit b5b901
      assert(loop->watchers[w->fd] == w);
Packit b5b901
      assert(loop->nfds > 0);
Packit b5b901
      loop->watchers[w->fd] = NULL;
Packit b5b901
      loop->nfds--;
Packit b5b901
      w->events = 0;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
  else if (QUEUE_EMPTY(&w->watcher_queue))
Packit b5b901
    QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
Packit b5b901
  uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
Packit b5b901
  QUEUE_REMOVE(&w->pending_queue);
Packit b5b901
Packit b5b901
  /* Remove stale events for this file descriptor */
Packit Service e08953
  if (w->fd != -1)
Packit Service e08953
    uv__platform_invalidate_fd(loop, w->fd);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
Packit b5b901
  if (QUEUE_EMPTY(&w->pending_queue))
Packit b5b901
    QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__io_active(const uv__io_t* w, unsigned int events) {
Packit b5b901
  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
Packit b5b901
  assert(0 != events);
Packit b5b901
  return 0 != (w->pevents & events);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__fd_exists(uv_loop_t* loop, int fd) {
Packit b5b901
  return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_getrusage(uv_rusage_t* rusage) {
Packit b5b901
  struct rusage usage;
Packit b5b901
Packit b5b901
  if (getrusage(RUSAGE_SELF, &usage))
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
Packit b5b901
  rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
Packit b5b901
Packit b5b901
  rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
Packit b5b901
  rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
Packit b5b901
Packit Service e08953
#if !defined(__MVS__) && !defined(__HAIKU__)
Packit b5b901
  rusage->ru_maxrss = usage.ru_maxrss;
Packit b5b901
  rusage->ru_ixrss = usage.ru_ixrss;
Packit b5b901
  rusage->ru_idrss = usage.ru_idrss;
Packit b5b901
  rusage->ru_isrss = usage.ru_isrss;
Packit b5b901
  rusage->ru_minflt = usage.ru_minflt;
Packit b5b901
  rusage->ru_majflt = usage.ru_majflt;
Packit b5b901
  rusage->ru_nswap = usage.ru_nswap;
Packit b5b901
  rusage->ru_inblock = usage.ru_inblock;
Packit b5b901
  rusage->ru_oublock = usage.ru_oublock;
Packit b5b901
  rusage->ru_msgsnd = usage.ru_msgsnd;
Packit b5b901
  rusage->ru_msgrcv = usage.ru_msgrcv;
Packit b5b901
  rusage->ru_nsignals = usage.ru_nsignals;
Packit b5b901
  rusage->ru_nvcsw = usage.ru_nvcsw;
Packit b5b901
  rusage->ru_nivcsw = usage.ru_nivcsw;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__open_cloexec(const char* path, int flags) {
Packit Service e08953
#if defined(O_CLOEXEC)
Packit b5b901
  int fd;
Packit b5b901
Packit Service e08953
  fd = open(path, flags | O_CLOEXEC);
Packit Service e08953
  if (fd == -1)
Packit Service e08953
    return UV__ERR(errno);
Packit b5b901
Packit Service e08953
  return fd;
Packit Service e08953
#else  /* O_CLOEXEC */
Packit Service e08953
  int err;
Packit Service e08953
  int fd;
Packit b5b901
Packit b5b901
  fd = open(path, flags);
Packit b5b901
  if (fd == -1)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  err = uv__cloexec(fd, 1);
Packit b5b901
  if (err) {
Packit b5b901
    uv__close(fd);
Packit b5b901
    return err;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return fd;
Packit Service e08953
#endif  /* O_CLOEXEC */
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__dup2_cloexec(int oldfd, int newfd) {
Packit Service e08953
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
Packit b5b901
  int r;
Packit Service e08953
Packit b5b901
  r = dup3(oldfd, newfd, O_CLOEXEC);
Packit b5b901
  if (r == -1)
Packit b5b901
    return UV__ERR(errno);
Packit Service e08953
Packit b5b901
  return r;
Packit b5b901
#else
Packit Service e08953
  int err;
Packit Service e08953
  int r;
Packit b5b901
Packit Service e08953
  r = dup2(oldfd, newfd);  /* Never retry. */
Packit Service e08953
  if (r == -1)
Packit Service e08953
    return UV__ERR(errno);
Packit b5b901
Packit Service e08953
  err = uv__cloexec(newfd, 1);
Packit Service e08953
  if (err != 0) {
Packit Service e08953
    uv__close(newfd);
Packit Service e08953
    return err;
Packit b5b901
  }
Packit Service e08953
Packit Service e08953
  return r;
Packit Service e08953
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_homedir(char* buffer, size_t* size) {
Packit b5b901
  uv_passwd_t pwd;
Packit b5b901
  size_t len;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  /* Check if the HOME environment variable is set first. The task of
Packit b5b901
     performing input validation on buffer and size is taken care of by
Packit b5b901
     uv_os_getenv(). */
Packit b5b901
  r = uv_os_getenv("HOME", buffer, size);
Packit b5b901
Packit b5b901
  if (r != UV_ENOENT)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  /* HOME is not set, so call uv__getpwuid_r() */
Packit b5b901
  r = uv__getpwuid_r(&pwd);
Packit b5b901
Packit b5b901
  if (r != 0) {
Packit b5b901
    return r;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  len = strlen(pwd.homedir);
Packit b5b901
Packit b5b901
  if (len >= *size) {
Packit b5b901
    *size = len + 1;
Packit b5b901
    uv_os_free_passwd(&pwd);
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, pwd.homedir, len + 1);
Packit b5b901
  *size = len;
Packit b5b901
  uv_os_free_passwd(&pwd);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_tmpdir(char* buffer, size_t* size) {
Packit b5b901
  const char* buf;
Packit b5b901
  size_t len;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
#define CHECK_ENV_VAR(name)                                                   \
Packit b5b901
  do {                                                                        \
Packit b5b901
    buf = getenv(name);                                                       \
Packit b5b901
    if (buf != NULL)                                                          \
Packit b5b901
      goto return_buffer;                                                     \
Packit b5b901
  }                                                                           \
Packit b5b901
  while (0)
Packit b5b901
Packit b5b901
  /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */
Packit b5b901
  CHECK_ENV_VAR("TMPDIR");
Packit b5b901
  CHECK_ENV_VAR("TMP");
Packit b5b901
  CHECK_ENV_VAR("TEMP");
Packit b5b901
  CHECK_ENV_VAR("TEMPDIR");
Packit b5b901
Packit b5b901
#undef CHECK_ENV_VAR
Packit b5b901
Packit b5b901
  /* No temp environment variables defined */
Packit b5b901
  #if defined(__ANDROID__)
Packit b5b901
    buf = "/data/local/tmp";
Packit b5b901
  #else
Packit b5b901
    buf = "/tmp";
Packit b5b901
  #endif
Packit b5b901
Packit b5b901
return_buffer:
Packit b5b901
  len = strlen(buf);
Packit b5b901
Packit b5b901
  if (len >= *size) {
Packit b5b901
    *size = len + 1;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* The returned directory should not have a trailing slash. */
Packit b5b901
  if (len > 1 && buf[len - 1] == '/') {
Packit b5b901
    len--;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, buf, len + 1);
Packit b5b901
  buffer[len] = '\0';
Packit b5b901
  *size = len;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__getpwuid_r(uv_passwd_t* pwd) {
Packit b5b901
  struct passwd pw;
Packit b5b901
  struct passwd* result;
Packit b5b901
  char* buf;
Packit b5b901
  uid_t uid;
Packit b5b901
  size_t bufsize;
Packit b5b901
  size_t name_size;
Packit b5b901
  size_t homedir_size;
Packit b5b901
  size_t shell_size;
Packit b5b901
  long initsize;
Packit b5b901
  int r;
Packit b5b901
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
Packit b5b901
  int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
Packit b5b901
Packit b5b901
  getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
Packit b5b901
  if (getpwuid_r == NULL)
Packit b5b901
    return UV_ENOSYS;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  if (pwd == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
Packit b5b901
Packit b5b901
  if (initsize <= 0)
Packit b5b901
    bufsize = 4096;
Packit b5b901
  else
Packit b5b901
    bufsize = (size_t) initsize;
Packit b5b901
Packit b5b901
  uid = geteuid();
Packit b5b901
  buf = NULL;
Packit b5b901
Packit b5b901
  for (;;) {
Packit b5b901
    uv__free(buf);
Packit b5b901
    buf = uv__malloc(bufsize);
Packit b5b901
Packit b5b901
    if (buf == NULL)
Packit b5b901
      return UV_ENOMEM;
Packit b5b901
Packit b5b901
    r = getpwuid_r(uid, &pw, buf, bufsize, &result);
Packit b5b901
Packit b5b901
    if (r != ERANGE)
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    bufsize *= 2;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (r != 0) {
Packit b5b901
    uv__free(buf);
Packit b5b901
    return -r;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (result == NULL) {
Packit b5b901
    uv__free(buf);
Packit b5b901
    return UV_ENOENT;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Allocate memory for the username, shell, and home directory */
Packit b5b901
  name_size = strlen(pw.pw_name) + 1;
Packit b5b901
  homedir_size = strlen(pw.pw_dir) + 1;
Packit b5b901
  shell_size = strlen(pw.pw_shell) + 1;
Packit b5b901
  pwd->username = uv__malloc(name_size + homedir_size + shell_size);
Packit b5b901
Packit b5b901
  if (pwd->username == NULL) {
Packit b5b901
    uv__free(buf);
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Copy the username */
Packit b5b901
  memcpy(pwd->username, pw.pw_name, name_size);
Packit b5b901
Packit b5b901
  /* Copy the home directory */
Packit b5b901
  pwd->homedir = pwd->username + name_size;
Packit b5b901
  memcpy(pwd->homedir, pw.pw_dir, homedir_size);
Packit b5b901
Packit b5b901
  /* Copy the shell */
Packit b5b901
  pwd->shell = pwd->homedir + homedir_size;
Packit b5b901
  memcpy(pwd->shell, pw.pw_shell, shell_size);
Packit b5b901
Packit b5b901
  /* Copy the uid and gid */
Packit b5b901
  pwd->uid = pw.pw_uid;
Packit b5b901
  pwd->gid = pw.pw_gid;
Packit b5b901
Packit b5b901
  uv__free(buf);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_os_free_passwd(uv_passwd_t* pwd) {
Packit b5b901
  if (pwd == NULL)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  /*
Packit b5b901
    The memory for name, shell, and homedir are allocated in a single
Packit b5b901
    uv__malloc() call. The base of the pointer is stored in pwd->username, so
Packit b5b901
    that is the field that needs to be freed.
Packit b5b901
  */
Packit b5b901
  uv__free(pwd->username);
Packit b5b901
  pwd->username = NULL;
Packit b5b901
  pwd->shell = NULL;
Packit b5b901
  pwd->homedir = NULL;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_get_passwd(uv_passwd_t* pwd) {
Packit b5b901
  return uv__getpwuid_r(pwd);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_translate_sys_error(int sys_errno) {
Packit b5b901
  /* If < 0 then it's already a libuv error. */
Packit b5b901
  return sys_errno <= 0 ? sys_errno : -sys_errno;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
int uv_os_environ(uv_env_item_t** envitems, int* count) {
Packit Service e08953
  int i, j, cnt;
Packit Service e08953
  uv_env_item_t* envitem;
Packit Service e08953
Packit Service e08953
  *envitems = NULL;
Packit Service e08953
  *count = 0;
Packit Service e08953
Packit Service e08953
  for (i = 0; environ[i] != NULL; i++);
Packit Service e08953
Packit Service e08953
  *envitems = uv__calloc(i, sizeof(**envitems));
Packit Service e08953
Packit Service e08953
  if (*envitems == NULL)
Packit Service e08953
    return UV_ENOMEM;
Packit Service e08953
Packit Service e08953
  for (j = 0, cnt = 0; j < i; j++) {
Packit Service e08953
    char* buf;
Packit Service e08953
    char* ptr;
Packit Service e08953
Packit Service e08953
    if (environ[j] == NULL)
Packit Service e08953
      break;
Packit Service e08953
Packit Service e08953
    buf = uv__strdup(environ[j]);
Packit Service e08953
    if (buf == NULL)
Packit Service e08953
      goto fail;
Packit Service e08953
Packit Service e08953
    ptr = strchr(buf, '=');
Packit Service e08953
    if (ptr == NULL) {
Packit Service e08953
      uv__free(buf);
Packit Service e08953
      continue;
Packit Service e08953
    }
Packit Service e08953
Packit Service e08953
    *ptr = '\0';
Packit Service e08953
Packit Service e08953
    envitem = &(*envitems)[cnt];
Packit Service e08953
    envitem->name = buf;
Packit Service e08953
    envitem->value = ptr + 1;
Packit Service e08953
Packit Service e08953
    cnt++;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  *count = cnt;
Packit Service e08953
  return 0;
Packit Service e08953
Packit Service e08953
fail:
Packit Service e08953
  for (i = 0; i < cnt; i++) {
Packit Service e08953
    envitem = &(*envitems)[cnt];
Packit Service e08953
    uv__free(envitem->name);
Packit Service e08953
  }
Packit Service e08953
  uv__free(*envitems);
Packit Service e08953
Packit Service e08953
  *envitems = NULL;
Packit Service e08953
  *count = 0;
Packit Service e08953
  return UV_ENOMEM;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
Packit b5b901
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
Packit b5b901
  char* var;
Packit b5b901
  size_t len;
Packit b5b901
Packit b5b901
  if (name == NULL || buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  var = getenv(name);
Packit b5b901
Packit b5b901
  if (var == NULL)
Packit b5b901
    return UV_ENOENT;
Packit b5b901
Packit b5b901
  len = strlen(var);
Packit b5b901
Packit b5b901
  if (len >= *size) {
Packit b5b901
    *size = len + 1;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, var, len + 1);
Packit b5b901
  *size = len;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_setenv(const char* name, const char* value) {
Packit b5b901
  if (name == NULL || value == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  if (setenv(name, value, 1) != 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_unsetenv(const char* name) {
Packit b5b901
  if (name == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  if (unsetenv(name) != 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_gethostname(char* buffer, size_t* size) {
Packit b5b901
  /*
Packit b5b901
    On some platforms, if the input buffer is not large enough, gethostname()
Packit b5b901
    succeeds, but truncates the result. libuv can detect this and return ENOBUFS
Packit b5b901
    instead by creating a large enough buffer and comparing the hostname length
Packit b5b901
    to the size input.
Packit b5b901
  */
Packit Service e08953
  char buf[UV_MAXHOSTNAMESIZE];
Packit b5b901
  size_t len;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  if (gethostname(buf, sizeof(buf)) != 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
Packit b5b901
  len = strlen(buf);
Packit b5b901
Packit b5b901
  if (len >= *size) {
Packit b5b901
    *size = len + 1;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, buf, len + 1);
Packit b5b901
  *size = len;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uv_os_fd_t uv_get_osfhandle(int fd) {
Packit b5b901
  return fd;
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv_open_osfhandle(uv_os_fd_t os_fd) {
Packit b5b901
  return os_fd;
Packit b5b901
}
Packit b5b901
Packit b5b901
uv_pid_t uv_os_getpid(void) {
Packit b5b901
  return getpid();
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uv_pid_t uv_os_getppid(void) {
Packit b5b901
  return getppid();
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_getpriority(uv_pid_t pid, int* priority) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (priority == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  errno = 0;
Packit b5b901
  r = getpriority(PRIO_PROCESS, (int) pid);
Packit b5b901
Packit b5b901
  if (r == -1 && errno != 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  *priority = r;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_setpriority(uv_pid_t pid, int priority) {
Packit b5b901
  if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit Service e08953
Packit Service e08953
Packit Service e08953
int uv_os_uname(uv_utsname_t* buffer) {
Packit Service e08953
  struct utsname buf;
Packit Service e08953
  int r;
Packit Service e08953
Packit Service e08953
  if (buffer == NULL)
Packit Service e08953
    return UV_EINVAL;
Packit Service e08953
Packit Service e08953
  if (uname(&buf) == -1) {
Packit Service e08953
    r = UV__ERR(errno);
Packit Service e08953
    goto error;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
Packit Service e08953
  if (r == UV_E2BIG)
Packit Service e08953
    goto error;
Packit Service e08953
Packit Service e08953
#ifdef _AIX
Packit Service e08953
  r = snprintf(buffer->release,
Packit Service e08953
               sizeof(buffer->release),
Packit Service e08953
               "%s.%s",
Packit Service e08953
               buf.version,
Packit Service e08953
               buf.release);
Packit Service e08953
  if (r >= sizeof(buffer->release)) {
Packit Service e08953
    r = UV_E2BIG;
Packit Service e08953
    goto error;
Packit Service e08953
  }
Packit Service e08953
#else
Packit Service e08953
  r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
Packit Service e08953
  if (r == UV_E2BIG)
Packit Service e08953
    goto error;
Packit Service e08953
#endif
Packit Service e08953
Packit Service e08953
  r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
Packit Service e08953
  if (r == UV_E2BIG)
Packit Service e08953
    goto error;
Packit Service e08953
Packit Service e08953
#if defined(_AIX) || defined(__PASE__)
Packit Service e08953
  r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
Packit Service e08953
#else
Packit Service e08953
  r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
Packit Service e08953
#endif
Packit Service e08953
Packit Service e08953
  if (r == UV_E2BIG)
Packit Service e08953
    goto error;
Packit Service e08953
Packit Service e08953
  return 0;
Packit Service e08953
Packit Service e08953
error:
Packit Service e08953
  buffer->sysname[0] = '\0';
Packit Service e08953
  buffer->release[0] = '\0';
Packit Service e08953
  buffer->version[0] = '\0';
Packit Service e08953
  buffer->machine[0] = '\0';
Packit Service e08953
  return r;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
int uv__getsockpeername(const uv_handle_t* handle,
Packit Service e08953
                        uv__peersockfunc func,
Packit Service e08953
                        struct sockaddr* name,
Packit Service e08953
                        int* namelen) {
Packit Service e08953
  socklen_t socklen;
Packit Service e08953
  uv_os_fd_t fd;
Packit Service e08953
  int r;
Packit Service e08953
Packit Service e08953
  r = uv_fileno(handle, &fd;;
Packit Service e08953
  if (r < 0)
Packit Service e08953
    return r;
Packit Service e08953
Packit Service e08953
  /* sizeof(socklen_t) != sizeof(int) on some systems. */
Packit Service e08953
  socklen = (socklen_t) *namelen;
Packit Service e08953
Packit Service e08953
  if (func(fd, name, &socklen))
Packit Service e08953
    return UV__ERR(errno);
Packit Service e08953
Packit Service e08953
  *namelen = (int) socklen;
Packit Service e08953
  return 0;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
int uv_gettimeofday(uv_timeval64_t* tv) {
Packit Service e08953
  struct timeval time;
Packit Service e08953
Packit Service e08953
  if (tv == NULL)
Packit Service e08953
    return UV_EINVAL;
Packit Service e08953
Packit Service e08953
  if (gettimeofday(&time, NULL) != 0)
Packit Service e08953
    return UV__ERR(errno);
Packit Service e08953
Packit Service e08953
  tv->tv_sec = (int64_t) time.tv_sec;
Packit Service e08953
  tv->tv_usec = (int32_t) time.tv_usec;
Packit Service e08953
  return 0;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
void uv_sleep(unsigned int msec) {
Packit Service e08953
  struct timespec timeout;
Packit Service e08953
  int rc;
Packit Service e08953
Packit Service e08953
  timeout.tv_sec = msec / 1000;
Packit Service e08953
  timeout.tv_nsec = (msec % 1000) * 1000 * 1000;
Packit Service e08953
Packit Service e08953
  do
Packit Service e08953
    rc = nanosleep(&timeout, &timeout);
Packit Service e08953
  while (rc == -1 && errno == EINTR);
Packit Service e08953
Packit Service e08953
  assert(rc == 0);
Packit Service e08953
}