int uv__cloexec_fcntl(int fd, int set) { int flags; int r; do r = fcntl(fd, F_GETFD); while (r == -1 && errno == EINTR); if (r == -1) return UV__ERR(errno); /* Bail out now if already set/clear. */ if (!!(r & FD_CLOEXEC) == !!set) return 0; if (set) flags = r | FD_CLOEXEC; else flags = r & ~FD_CLOEXEC; do r = fcntl(fd, F_SETFD, flags); while (r == -1 && errno == EINTR); if (r) return UV__ERR(errno); return 0; }
int uv__nonblock_fcntl(int fd, int set) { int flags; int r; do r = fcntl(fd, F_GETFL); while (r == -1 && errno == EINTR); if (r == -1) return UV__ERR(errno); /* Bail out now if already set/clear. */ if (!!(r & O_NONBLOCK) == !!set) return 0; if (set) flags = r | O_NONBLOCK; else flags = r & ~O_NONBLOCK; do r = fcntl(fd, F_SETFL, flags); while (r == -1 && errno == EINTR); if (r) return UV__ERR(errno); return 0; }
int uv__open_cloexec(const char* path, int flags) { int err; int fd; #if defined(UV__O_CLOEXEC) static int no_cloexec; if (!no_cloexec) { fd = open(path, flags | UV__O_CLOEXEC); if (fd != -1) return fd; if (errno != EINVAL) return UV__ERR(errno); /* O_CLOEXEC not supported. */ no_cloexec = 1; } #endif fd = open(path, flags); if (fd == -1) return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err) { uv__close(fd); return err; } return fd; }
int uv_cond_init(uv_cond_t* cond) { pthread_condattr_t attr; int err; err = pthread_condattr_init(&attr); if (err) return UV__ERR(err); #if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); if (err) goto error2; #endif err = pthread_cond_init(cond, &attr); if (err) goto error2; err = pthread_condattr_destroy(&attr); if (err) goto error; return 0; error: pthread_cond_destroy(cond); error2: pthread_condattr_destroy(&attr); return UV__ERR(err); }
int uv__make_pipe(int fds[2], int flags) { #if defined(__linux__) static int no_pipe2; if (no_pipe2) goto skip; if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0) return 0; if (errno != ENOSYS) return UV__ERR(errno); no_pipe2 = 1; skip: #endif if (pipe(fds)) return UV__ERR(errno); uv__cloexec(fds[0], 1); uv__cloexec(fds[1], 1); if (flags & UV__F_NONBLOCK) { uv__nonblock(fds[0], 1); uv__nonblock(fds[1], 1); } return 0; }
int uv__make_socketpair(int fds[2], int flags) { #if defined(__linux__) static int no_cloexec; if (no_cloexec) goto skip; if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0) return 0; /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported. * Anything else is a genuine error. */ if (errno != EINVAL) return UV__ERR(errno); no_cloexec = 1; skip: #endif if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) return UV__ERR(errno); uv__cloexec(fds[0], 1); uv__cloexec(fds[1], 1); if (flags & UV__F_NONBLOCK) { uv__nonblock(fds[0], 1); uv__nonblock(fds[1], 1); } return 0; }
int uv_sem_init(uv_sem_t* sem, unsigned int value) { uv_sem_t semid; int err; union { int val; struct semid_ds* buf; unsigned short* array; } arg; semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); if (semid == -1) return UV__ERR(errno); arg.val = value; if (-1 == semctl(semid, 0, SETVAL, arg)) { err = errno; if (-1 == semctl(*sem, 0, IPC_RMID)) abort(); return UV__ERR(err); } *sem = semid; return 0; }
/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ int uv__socket(int domain, int type, int protocol) { int sockfd; int err; #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (sockfd != -1) return sockfd; if (errno != EINVAL) return UV__ERR(errno); #endif sockfd = socket(domain, type, protocol); if (sockfd == -1) return UV__ERR(errno); err = uv__nonblock(sockfd, 1); if (err == 0) err = uv__cloexec(sockfd, 1); if (err) { uv__close(sockfd); return err; } #if defined(SO_NOSIGPIPE) { int on = 1; setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); } #endif return sockfd; }
/* * Checks if /aha is mounted, then proceeds to set up the monitoring * objects for the specified file. * Returns 0 on success, or an error code < 0 on failure */ static int uv__setup_ahafs(const char* filename, int *fd) { int rc = 0; char mon_file_write_string[RDWR_BUF_SIZE]; char mon_file[PATH_MAX]; int file_is_directory = 0; /* -1 == NO, 0 == YES */ /* Create monitor file name for object */ file_is_directory = uv__path_is_a_directory((char*)filename); if (file_is_directory == 0) sprintf(mon_file, "/aha/fs/modDir.monFactory"); else sprintf(mon_file, "/aha/fs/modFile.monFactory"); if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) return UV_ENAMETOOLONG; /* Make the necessary subdirectories for the monitor file */ rc = uv__make_subdirs_p(filename); if (rc == -1 && errno != EEXIST) return rc; strcat(mon_file, filename); strcat(mon_file, ".mon"); *fd = 0; errno = 0; /* Open the monitor file, creating it if necessary */ *fd = open(mon_file, O_CREAT|O_RDWR); if (*fd < 0) return UV__ERR(errno); /* Write out the monitoring specifications. * In this case, we are monitoring for a state change event type * CHANGED=YES * We will be waiting in select call, rather than a read: * WAIT_TYPE=WAIT_IN_SELECT * We only want minimal information for files: * INFO_LVL=1 * For directories, we want more information to track what file * caused the change * INFO_LVL=2 */ if (file_is_directory == 0) sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2"); else sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); if (rc < 0 && errno != EBUSY) return UV__ERR(errno); return 0; }
int uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; ssize_t n; long val; int fd; int i; do fd = open("/proc/self/stat", O_RDONLY); while (fd == -1 && errno == EINTR); if (fd == -1) return UV__ERR(errno); do n = read(fd, buf, sizeof(buf) - 1); while (n == -1 && errno == EINTR); uv__close(fd); if (n == -1) return UV__ERR(errno); buf[n] = '\0'; s = strchr(buf, ' '); if (s == NULL) goto err; s += 1; if (*s != '(') goto err; s = strchr(s, ')'); if (s == NULL) goto err; for (i = 1; i <= 22; i++) { s = strchr(s + 1, ' '); if (s == NULL) goto err; } errno = 0; val = strtol(s, NULL, 10); if (errno != 0) goto err; if (val < 0) goto err; *rss = val * getpagesize(); return 0; err: return UV_EINVAL; }
int uv__accept(int sockfd) { int peerfd; int err; assert(sockfd >= 0); while (1) { #if defined(__linux__) || \ (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ defined(__NetBSD__) static int no_accept4; if (no_accept4) goto skip; peerfd = uv__accept4(sockfd, NULL, NULL, UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); if (peerfd != -1) return peerfd; if (errno == EINTR) continue; if (errno != ENOSYS) return UV__ERR(errno); no_accept4 = 1; skip: #endif peerfd = accept(sockfd, NULL, NULL); if (peerfd == -1) { if (errno == EINTR) continue; return UV__ERR(errno); } err = uv__cloexec(peerfd, 1); if (err == 0) err = uv__nonblock(peerfd, 1); if (err) { uv__close(peerfd); return err; } return peerfd; } }
int uv__dup2_cloexec(int oldfd, int newfd) { int r; #if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) return UV__ERR(errno); return r; #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); if (r != -1) return r; if (errno != EINVAL) return UV__ERR(errno); /* Fall through. */ #elif defined(__linux__) static int no_dup3; if (!no_dup3) { do r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); while (r == -1 && errno == EBUSY); if (r != -1) return r; if (errno != ENOSYS) return UV__ERR(errno); /* Fall through. */ no_dup3 = 1; } #endif { int err; do r = dup2(oldfd, newfd); #if defined(__linux__) while (r == -1 && errno == EBUSY); #else while (0); /* Never retry. */ #endif if (r == -1) return UV__ERR(errno); err = uv__cloexec(newfd, 1); if (err) { uv__close(newfd); return err; } return r; } }
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { int err; size_t stack_size; pthread_attr_t* attr; pthread_attr_t attr_storage; attr = NULL; stack_size = thread_stack_size(); if (stack_size > 0) { attr = &attr_storage; if (pthread_attr_init(attr)) abort(); if (pthread_attr_setstacksize(attr, stack_size)) abort(); } err = pthread_create(tid, attr, (void*(*)(void*)) (void(*)(void)) entry, arg); if (attr != NULL) pthread_attr_destroy(attr); return UV__ERR(err); }
/* * Creates necessary subdirectories in the AIX Event Infrastructure * file system for monitoring the object specified. * Returns code from mkdir call */ static int uv__make_subdirs_p(const char *filename) { char cmd[2048]; char *p; int rc = 0; /* Strip off the monitor file name */ p = strrchr(filename, '/'); if (p == NULL) return 0; if (uv__path_is_a_directory((char*)filename) == 0) { sprintf(cmd, "/aha/fs/modDir.monFactory"); } else { sprintf(cmd, "/aha/fs/modFile.monFactory"); } strncat(cmd, filename, (p - filename)); rc = uv__makedir_p(cmd); if (rc == -1 && errno != EEXIST){ return UV__ERR(errno); } return rc; }
int uv_os_gethostname(char* buffer, size_t* size) { /* On some platforms, if the input buffer is not large enough, gethostname() succeeds, but truncates the result. libuv can detect this and return ENOBUFS instead by creating a large enough buffer and comparing the hostname length to the size input. */ char buf[MAXHOSTNAMELEN + 1]; size_t len; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; if (gethostname(buf, sizeof(buf)) != 0) return UV__ERR(errno); buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ len = strlen(buf); if (len >= *size) { *size = len + 1; return UV_ENOBUFS; } memcpy(buffer, buf, len + 1); *size = len; return 0; }
int uv_getrusage(uv_rusage_t* rusage) { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage)) return UV__ERR(errno); rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec; rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; #if !defined(__MVS__) rusage->ru_maxrss = usage.ru_maxrss; rusage->ru_ixrss = usage.ru_ixrss; rusage->ru_idrss = usage.ru_idrss; rusage->ru_isrss = usage.ru_isrss; rusage->ru_minflt = usage.ru_minflt; rusage->ru_majflt = usage.ru_majflt; rusage->ru_nswap = usage.ru_nswap; rusage->ru_inblock = usage.ru_inblock; rusage->ru_oublock = usage.ru_oublock; rusage->ru_msgsnd = usage.ru_msgsnd; rusage->ru_msgrcv = usage.ru_msgrcv; rusage->ru_nsignals = usage.ru_nsignals; rusage->ru_nvcsw = usage.ru_nvcsw; rusage->ru_nivcsw = usage.ru_nivcsw; #endif return 0; }
int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t fd) { int flags; int mode; int err; flags = 0; if (uv__fd_exists(handle->loop, fd)) return UV_EEXIST; do mode = fcntl(fd, F_GETFL); while (mode == -1 && errno == EINTR); if (mode == -1) return UV__ERR(errno); /* according to docs, must be EBADF */ err = uv__nonblock(fd, 1); if (err) return err; #if defined(__APPLE__) err = uv__stream_try_select((uv_stream_t*) handle, &fd); if (err) return err; #endif /* defined(__APPLE__) */ mode &= O_ACCMODE; if (mode != O_WRONLY) flags |= UV_HANDLE_READABLE; if (mode != O_RDONLY) flags |= UV_HANDLE_WRITABLE; return uv__stream_open((uv_stream_t*)handle, fd, flags); }
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { int r; int fd; socklen_t len; if (handle == NULL || value == NULL) return UV_EINVAL; if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE) fd = uv__stream_fd((uv_stream_t*) handle); else if (handle->type == UV_UDP) fd = ((uv_udp_t *) handle)->io_watcher.fd; else return UV_ENOTSUP; len = sizeof(*value); if (*value == 0) r = getsockopt(fd, SOL_SOCKET, optname, value, &len); else r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len); if (r < 0) return UV__ERR(errno); return 0; }
int uv__close_nocheckstdio(int fd) { int saved_errno; int rc; assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ saved_errno = errno; rc = close(fd); if (rc == -1) { rc = UV__ERR(errno); if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS)) rc = 0; /* The close is in progress, not an error. */ errno = saved_errno; } return rc; }
/* * Check whether AHAFS is mounted. * Returns 0 if AHAFS is mounted, or an error code < 0 on failure */ static int uv__is_ahafs_mounted(void){ char rawbuf[FILENAME_MAX+1]; int rv, i = 2; struct vmount *p; int size_multiplier = 10; size_t siz = sizeof(struct vmount)*size_multiplier; struct vmount *vmt; const char *dev = "/aha"; char *obj, *stub; p = uv__malloc(siz); if (p == NULL) return UV__ERR(errno); /* Retrieve all mounted filesystems */ rv = mntctl(MCTL_QUERY, siz, (char*)p); if (rv < 0) return UV__ERR(errno); if (rv == 0) { /* buffer was not large enough, reallocate to correct size */ siz = *(int*)p; uv__free(p); p = uv__malloc(siz); if (p == NULL) return UV__ERR(errno); rv = mntctl(MCTL_QUERY, siz, (char*)p); if (rv < 0) return UV__ERR(errno); } /* Look for dev in filesystems mount info */ for(vmt = p, i = 0; i < rv; i++) { obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) { uv__free(p); /* Found a match */ return 0; } vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length); } /* /aha is required for monitoring filesystem changes */ return -1; }
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { struct termios tmp; int fd; if (tty->mode == (int) mode) return 0; fd = uv__stream_fd(tty); if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { if (tcgetattr(fd, &tty->orig_termios)) return UV__ERR(errno); /* This is used for uv_tty_reset_mode() */ uv_spinlock_lock(&termios_spinlock); if (orig_termios_fd == -1) { orig_termios = tty->orig_termios; orig_termios_fd = fd; } uv_spinlock_unlock(&termios_spinlock); } tmp = tty->orig_termios; switch (mode) { case UV_TTY_MODE_NORMAL: break; case UV_TTY_MODE_RAW: tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); tmp.c_oflag |= (ONLCR); tmp.c_cflag |= (CS8); tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); tmp.c_cc[VMIN] = 1; tmp.c_cc[VTIME] = 0; break; case UV_TTY_MODE_IO: uv__tty_make_raw(&tmp); break; } /* Apply changes after draining */ if (tcsetattr(fd, TCSADRAIN, &tmp)) return UV__ERR(errno); tty->mode = mode; return 0; }
int uv__getaddrinfo_translate_error(int sys_err) { switch (sys_err) { case 0: return 0; #if defined(EAI_ADDRFAMILY) case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; #endif #if defined(EAI_AGAIN) case EAI_AGAIN: return UV_EAI_AGAIN; #endif #if defined(EAI_BADFLAGS) case EAI_BADFLAGS: return UV_EAI_BADFLAGS; #endif #if defined(EAI_BADHINTS) case EAI_BADHINTS: return UV_EAI_BADHINTS; #endif #if defined(EAI_CANCELED) case EAI_CANCELED: return UV_EAI_CANCELED; #endif #if defined(EAI_FAIL) case EAI_FAIL: return UV_EAI_FAIL; #endif #if defined(EAI_FAMILY) case EAI_FAMILY: return UV_EAI_FAMILY; #endif #if defined(EAI_MEMORY) case EAI_MEMORY: return UV_EAI_MEMORY; #endif #if defined(EAI_NODATA) case EAI_NODATA: return UV_EAI_NODATA; #endif #if defined(EAI_NONAME) # if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME case EAI_NONAME: return UV_EAI_NONAME; # endif #endif #if defined(EAI_OVERFLOW) case EAI_OVERFLOW: return UV_EAI_OVERFLOW; #endif #if defined(EAI_PROTOCOL) case EAI_PROTOCOL: return UV_EAI_PROTOCOL; #endif #if defined(EAI_SERVICE) case EAI_SERVICE: return UV_EAI_SERVICE; #endif #if defined(EAI_SOCKTYPE) case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; #endif #if defined(EAI_SYSTEM) case EAI_SYSTEM: return UV__ERR(errno); #endif } assert(!"unknown EAI_* error code"); abort(); #ifndef __SUNPRO_C return 0; /* Pacify compiler. */ #endif }
int uv_os_setenv(const char* name, const char* value) { if (name == NULL || value == NULL) return UV_EINVAL; if (setenv(name, value, 1) != 0) return UV__ERR(errno); return 0; }
int uv_os_unsetenv(const char* name) { if (name == NULL) return UV_EINVAL; if (unsetenv(name) != 0) return UV__ERR(errno); return 0; }
int uv_os_setpriority(uv_pid_t pid, int priority) { if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) return UV_EINVAL; if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0) return UV__ERR(errno); return 0; }
int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un saddr; const char* pipe_fname; int sockfd; int err; size_t name_len; pipe_fname = NULL; sockfd = -1; name_len = strlen(name); if (name_len > sizeof(saddr.sun_path) - 1) return -ENAMETOOLONG; /* Already bound? */ if (uv__stream_fd(handle) >= 0) return UV_EINVAL; /* Make a copy of the file name, it outlives this function's scope. */ pipe_fname = uv__strdup(name); if (pipe_fname == NULL) return UV_ENOMEM; /* We've got a copy, don't touch the original any more. */ name = NULL; err = uv__socket(AF_UNIX, SOCK_STREAM, 0); if (err < 0) goto err_socket; sockfd = err; memset(&saddr, 0, sizeof saddr); memcpy(saddr.sun_path, pipe_fname, name_len); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { err = UV__ERR(errno); /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == UV_ENOENT) err = UV_EACCES; uv__close(sockfd); goto err_socket; } /* Success. */ handle->flags |= UV_HANDLE_BOUND; handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ handle->io_watcher.fd = sockfd; return 0; err_socket: uv__free((void*)pipe_fname); return err; }
int uv_os_uname(uv_utsname_t* buffer) { struct utsname buf; int r; if (buffer == NULL) return UV_EINVAL; if (uname(&buf) == -1) { r = UV__ERR(errno); goto error; } r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname)); if (r == UV_E2BIG) goto error; #ifdef _AIX r = snprintf(buffer->release, sizeof(buffer->release), "%s.%s", buf.version, buf.release); if (r >= sizeof(buffer->release)) { r = UV_E2BIG; goto error; } #else r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release)); if (r == UV_E2BIG) goto error; #endif r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version)); if (r == UV_E2BIG) goto error; #if defined(_AIX) || defined(__PASE__) r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine)); #else r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine)); #endif if (r == UV_E2BIG) goto error; return 0; error: buffer->sysname[0] = '\0'; buffer->release[0] = '\0'; buffer->version[0] = '\0'; buffer->machine[0] = '\0'; return r; }
int uv_mutex_init(uv_mutex_t* mutex) { #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) return UV__ERR(pthread_mutex_init(mutex, NULL)); #else pthread_mutexattr_t attr; int err; if (pthread_mutexattr_init(&attr)) abort(); if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) abort(); err = pthread_mutex_init(mutex, &attr); if (pthread_mutexattr_destroy(&attr)) abort(); return UV__ERR(err); #endif }
int uv__cloexec_ioctl(int fd, int set) { int r; do r = ioctl(fd, set ? FIOCLEX : FIONCLEX); while (r == -1 && errno == EINTR); if (r) return UV__ERR(errno); return 0; }
int uv__nonblock_ioctl(int fd, int set) { int r; do r = ioctl(fd, FIONBIO, &set); while (r == -1 && errno == EINTR); if (r) return UV__ERR(errno); return 0; }