Alien-uv
view release on metacpan or search on metacpan
libuv/src/unix/core.c view on Meta::CPAN
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_os_homedir(char* buffer, size_t* size) {
uv_passwd_t pwd;
size_t len;
int r;
/* Check if the HOME environment variable is set first. The task of
performing input validation on buffer and size is taken care of by
uv_os_getenv(). */
r = uv_os_getenv("HOME", buffer, size);
if (r != UV_ENOENT)
return r;
/* HOME is not set, so call uv__getpwuid_r() */
r = uv__getpwuid_r(&pwd);
if (r != 0) {
return r;
}
len = strlen(pwd.homedir);
if (len >= *size) {
*size = len + 1;
uv_os_free_passwd(&pwd);
return UV_ENOBUFS;
}
memcpy(buffer, pwd.homedir, len + 1);
*size = len;
uv_os_free_passwd(&pwd);
return 0;
}
int uv_os_tmpdir(char* buffer, size_t* size) {
const char* buf;
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
#define CHECK_ENV_VAR(name) \
do { \
buf = getenv(name); \
if (buf != NULL) \
goto return_buffer; \
} \
while (0)
/* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */
CHECK_ENV_VAR("TMPDIR");
CHECK_ENV_VAR("TMP");
CHECK_ENV_VAR("TEMP");
CHECK_ENV_VAR("TEMPDIR");
#undef CHECK_ENV_VAR
/* No temp environment variables defined */
#if defined(__ANDROID__)
buf = "/data/local/tmp";
#else
buf = "/tmp";
#endif
return_buffer:
len = strlen(buf);
if (len >= *size) {
*size = len + 1;
return UV_ENOBUFS;
}
/* The returned directory should not have a trailing slash. */
if (len > 1 && buf[len - 1] == '/') {
len--;
}
memcpy(buffer, buf, len + 1);
buffer[len] = '\0';
*size = len;
return 0;
}
int uv__getpwuid_r(uv_passwd_t* pwd) {
struct passwd pw;
struct passwd* result;
char* buf;
uid_t uid;
size_t bufsize;
size_t name_size;
size_t homedir_size;
size_t shell_size;
long initsize;
int r;
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
if (getpwuid_r == NULL)
return UV_ENOSYS;
#endif
if (pwd == NULL)
return UV_EINVAL;
initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (initsize <= 0)
bufsize = 4096;
else
bufsize = (size_t) initsize;
uid = geteuid();
buf = NULL;
for (;;) {
uv__free(buf);
buf = uv__malloc(bufsize);
if (buf == NULL)
return UV_ENOMEM;
r = getpwuid_r(uid, &pw, buf, bufsize, &result);
if (r != ERANGE)
break;
bufsize *= 2;
}
if (r != 0) {
uv__free(buf);
return -r;
}
if (result == NULL) {
uv__free(buf);
return UV_ENOENT;
}
/* Allocate memory for the username, shell, and home directory */
name_size = strlen(pw.pw_name) + 1;
homedir_size = strlen(pw.pw_dir) + 1;
shell_size = strlen(pw.pw_shell) + 1;
pwd->username = uv__malloc(name_size + homedir_size + shell_size);
if (pwd->username == NULL) {
uv__free(buf);
return UV_ENOMEM;
}
/* Copy the username */
memcpy(pwd->username, pw.pw_name, name_size);
/* Copy the home directory */
pwd->homedir = pwd->username + name_size;
memcpy(pwd->homedir, pw.pw_dir, homedir_size);
/* Copy the shell */
pwd->shell = pwd->homedir + homedir_size;
memcpy(pwd->shell, pw.pw_shell, shell_size);
/* Copy the uid and gid */
pwd->uid = pw.pw_uid;
pwd->gid = pw.pw_gid;
uv__free(buf);
return 0;
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
/*
The memory for name, shell, and homedir are allocated in a single
uv__malloc() call. The base of the pointer is stored in pwd->username, so
that is the field that needs to be freed.
*/
uv__free(pwd->username);
pwd->username = NULL;
pwd->shell = NULL;
pwd->homedir = NULL;
}
int uv_os_get_passwd(uv_passwd_t* pwd) {
return uv__getpwuid_r(pwd);
}
int uv_translate_sys_error(int sys_errno) {
/* If < 0 then it's already a libuv error. */
return sys_errno <= 0 ? sys_errno : -sys_errno;
}
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
char* var;
size_t len;
if (name == NULL || buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
var = getenv(name);
if (var == NULL)
return UV_ENOENT;
len = strlen(var);
if (len >= *size) {
*size = len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, var, len + 1);
*size = len;
return 0;
}
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_gethostname(char* buffer, size_t* size) {
/*
On some platforms, if the input buffer is not large enough, gethostname()
( run in 0.332 second using v1.01-cache-2.11-cpan-3d66aa2751a )