2015-01-29 08:19:28 +01:00
|
|
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
2012-12-10 15:44:02 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2015-06-30 21:55:00 -07:00
|
|
|
#if !defined(_WIN32)
|
|
|
|
|
2013-12-23 21:01:57 -08:00
|
|
|
#include <stdint.h>
|
2012-04-03 10:32:26 -07:00
|
|
|
#include <time.h>
|
2013-12-23 21:01:57 -08:00
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
2012-02-07 18:55:02 -08:00
|
|
|
|
2015-05-11 12:24:56 -07:00
|
|
|
|
2013-12-23 21:01:57 -08:00
|
|
|
#include <dirent.h>
|
2015-04-15 23:21:13 -07:00
|
|
|
#include <pthread.h>
|
2013-12-23 21:01:57 -08:00
|
|
|
#include <signal.h>
|
2015-04-15 23:21:13 -07:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
2013-12-23 21:01:57 -08:00
|
|
|
#include <unistd.h>
|
2011-04-29 11:54:06 -07:00
|
|
|
|
2013-12-23 21:01:57 -08:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <TargetConditionals.h>
|
|
|
|
#include <mach/mach_time.h>
|
|
|
|
|
|
|
|
#if !(TARGET_OS_IPHONE)
|
|
|
|
#include <crt_externs.h>
|
|
|
|
#endif
|
2012-02-09 14:08:24 +08:00
|
|
|
#endif
|
|
|
|
|
2013-11-14 10:04:55 -08:00
|
|
|
char*
|
|
|
|
rust_list_dir_val(struct dirent* entry_ptr) {
|
2013-02-20 22:46:26 -08:00
|
|
|
return entry_ptr->d_name;
|
|
|
|
}
|
2015-04-15 23:21:13 -07:00
|
|
|
|
2015-08-09 13:15:50 +08:00
|
|
|
// Android's struct dirent does have d_type from the very beginning
|
|
|
|
// (android-3). _DIRENT_HAVE_D_TYPE is not defined all the way to android-21
|
|
|
|
// though...
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
# define _DIRENT_HAVE_D_TYPE
|
|
|
|
#endif
|
|
|
|
|
2015-04-15 23:21:13 -07:00
|
|
|
int
|
|
|
|
rust_dir_get_mode(struct dirent* entry_ptr) {
|
2015-05-19 17:48:03 -07:00
|
|
|
#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__)
|
2015-04-15 23:21:13 -07:00
|
|
|
switch (entry_ptr->d_type) {
|
|
|
|
case DT_BLK: return S_IFBLK;
|
|
|
|
case DT_CHR: return S_IFCHR;
|
|
|
|
case DT_FIFO: return S_IFIFO;
|
|
|
|
case DT_LNK: return S_IFLNK;
|
|
|
|
case DT_REG: return S_IFREG;
|
|
|
|
case DT_SOCK: return S_IFSOCK;
|
2015-05-19 17:48:03 -07:00
|
|
|
case DT_DIR: return S_IFDIR;
|
2015-04-15 23:21:13 -07:00
|
|
|
}
|
2011-07-12 15:14:57 -07:00
|
|
|
#endif
|
2015-04-15 23:21:13 -07:00
|
|
|
return -1;
|
|
|
|
}
|
2011-09-01 15:51:27 -07:00
|
|
|
|
2015-04-15 23:21:13 -07:00
|
|
|
ino_t
|
|
|
|
rust_dir_get_ino(struct dirent* entry_ptr) {
|
|
|
|
return entry_ptr->d_ino;
|
|
|
|
}
|
2013-03-12 20:06:20 -07:00
|
|
|
|
2013-11-14 10:04:55 -08:00
|
|
|
DIR*
|
2013-03-12 20:06:20 -07:00
|
|
|
rust_opendir(char *dirname) {
|
|
|
|
return opendir(dirname);
|
|
|
|
}
|
|
|
|
|
2014-03-04 17:27:43 -08:00
|
|
|
int
|
|
|
|
rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
|
|
|
return readdir_r(dirp, entry, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rust_dirent_t_size() {
|
|
|
|
return sizeof(struct dirent);
|
2013-03-12 20:06:20 -07:00
|
|
|
}
|
2013-08-09 22:21:01 -07:00
|
|
|
|
2015-06-30 21:55:00 -07:00
|
|
|
#if defined(__BSD__)
|
2015-09-05 05:03:48 +03:00
|
|
|
static int
|
2013-08-09 22:21:01 -07:00
|
|
|
get_num_cpus() {
|
|
|
|
/* swiped from http://stackoverflow.com/questions/150355/
|
|
|
|
programmatically-find-the-number-of-cores-on-a-machine */
|
|
|
|
|
|
|
|
unsigned int numCPU;
|
|
|
|
int mib[4];
|
|
|
|
size_t len = sizeof(numCPU);
|
|
|
|
|
|
|
|
/* set the mib for hw.ncpu */
|
|
|
|
mib[0] = CTL_HW;
|
|
|
|
mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
|
|
|
|
|
|
|
|
/* get the number of CPUs from the system */
|
|
|
|
sysctl(mib, 2, &numCPU, &len, NULL, 0);
|
|
|
|
|
|
|
|
if( numCPU < 1 ) {
|
|
|
|
mib[1] = HW_NCPU;
|
|
|
|
sysctl( mib, 2, &numCPU, &len, NULL, 0 );
|
|
|
|
|
|
|
|
if( numCPU < 1 ) {
|
|
|
|
numCPU = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return numCPU;
|
|
|
|
}
|
|
|
|
#elif defined(__GNUC__)
|
2015-09-05 05:03:48 +03:00
|
|
|
static int
|
2013-08-09 22:21:01 -07:00
|
|
|
get_num_cpus() {
|
|
|
|
return sysconf(_SC_NPROCESSORS_ONLN);
|
|
|
|
}
|
|
|
|
#endif
|
2013-06-05 22:34:35 -07:00
|
|
|
|
2013-11-14 10:04:55 -08:00
|
|
|
uintptr_t
|
2013-06-05 22:34:35 -07:00
|
|
|
rust_get_num_cpus() {
|
|
|
|
return get_num_cpus();
|
|
|
|
}
|
|
|
|
|
2014-07-29 16:44:39 +02:00
|
|
|
#if defined(__DragonFly__)
|
|
|
|
#include <errno.h>
|
|
|
|
// In DragonFly __error() is an inline function and as such
|
|
|
|
// no symbol exists for it.
|
|
|
|
int *__dfly_error(void) { return __error(); }
|
|
|
|
#endif
|
|
|
|
|
2015-01-16 23:51:04 -08:00
|
|
|
#if defined(__Bitrig__)
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
int rust_get_path(void *p, size_t* sz)
|
|
|
|
{
|
|
|
|
int mib[4];
|
|
|
|
char *eq = NULL;
|
|
|
|
char *key = NULL;
|
|
|
|
char *val = NULL;
|
|
|
|
char **menv = NULL;
|
|
|
|
size_t maxlen, len;
|
|
|
|
int nenv = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ((p == NULL) && (sz == NULL))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get the argv array */
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
mib[1] = KERN_PROC_ARGS;
|
|
|
|
mib[2] = getpid();
|
|
|
|
mib[3] = KERN_PROC_ENV;
|
|
|
|
|
|
|
|
/* get the number of bytes needed to get the env */
|
|
|
|
maxlen = 0;
|
|
|
|
if (sysctl(mib, 4, NULL, &maxlen, NULL, 0) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* allocate the buffer */
|
|
|
|
if ((menv = calloc(maxlen, sizeof(char))) == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get the env array */
|
|
|
|
if (sysctl(mib, 4, menv, &maxlen, NULL, 0) == -1)
|
|
|
|
{
|
|
|
|
free(menv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mib[3] = KERN_PROC_NENV;
|
|
|
|
len = sizeof(int);
|
|
|
|
/* get the length of env array */
|
|
|
|
if (sysctl(mib, 4, &nenv, &len, NULL, 0) == -1)
|
|
|
|
{
|
|
|
|
free(menv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find _ key and resolve the value */
|
|
|
|
for (i = 0; i < nenv; i++)
|
|
|
|
{
|
|
|
|
if ((eq = strstr(menv[i], "=")) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
key = menv[i];
|
|
|
|
val = eq + 1;
|
|
|
|
*eq = '\0';
|
|
|
|
|
|
|
|
if (strncmp(key, "PATH", maxlen) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
/* return the length of the value + NUL */
|
|
|
|
*sz = strnlen(val, maxlen) + 1;
|
|
|
|
free(menv);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* copy *sz bytes to the output buffer */
|
|
|
|
memcpy(p, val, *sz);
|
|
|
|
free(menv);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(menv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rust_get_path_array(void * p, size_t * sz)
|
|
|
|
{
|
|
|
|
char *path, *str;
|
|
|
|
char **buf;
|
|
|
|
int i, num;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if ((p == NULL) && (sz == NULL))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get the length of the PATH value */
|
|
|
|
if (rust_get_path(NULL, &len) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* allocate the buffer */
|
|
|
|
if ((path = calloc(len, sizeof(char))) == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get the PATH value */
|
|
|
|
if (rust_get_path(path, &len) == -1)
|
|
|
|
{
|
|
|
|
free(path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* count the number of parts in the PATH */
|
|
|
|
num = 1;
|
|
|
|
for(str = path; *str != '\0'; str++)
|
|
|
|
{
|
|
|
|
if (*str == ':')
|
|
|
|
num++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate the size of the buffer for the 2D array */
|
|
|
|
len = (num * sizeof(char*) + 1) + strlen(path) + 1;
|
|
|
|
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
free(path);
|
|
|
|
*sz = len;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure we have enough buffer space */
|
|
|
|
if (*sz < len)
|
|
|
|
{
|
|
|
|
free(path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* zero out the buffer */
|
|
|
|
buf = (char**)p;
|
|
|
|
memset(buf, 0, *sz);
|
|
|
|
|
|
|
|
/* copy the data into the right place */
|
|
|
|
str = p + ((num+1) * sizeof(char*));
|
|
|
|
memcpy(str, path, strlen(path));
|
|
|
|
|
|
|
|
/* parse the path into it's parts */
|
|
|
|
for (i = 0; i < num && (buf[i] = strsep(&str, ":")) != NULL; i++) {;}
|
|
|
|
buf[num] = NULL;
|
|
|
|
|
|
|
|
free(path);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rust_get_argv_zero(void* p, size_t* sz)
|
|
|
|
{
|
|
|
|
int mib[4];
|
|
|
|
char **argv = NULL;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if ((p == NULL) && (sz == NULL))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get the argv array */
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
mib[1] = KERN_PROC_ARGS;
|
|
|
|
mib[2] = getpid();
|
|
|
|
mib[3] = KERN_PROC_ARGV;
|
|
|
|
|
|
|
|
/* request KERN_PROC_ARGV size */
|
|
|
|
len = 0;
|
|
|
|
if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* allocate buffer to receive the values */
|
|
|
|
if ((argv = malloc(len)) == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get the argv array */
|
|
|
|
if (sysctl(mib, 4, argv, &len, NULL, 0) == -1)
|
|
|
|
{
|
|
|
|
free(argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get length of argv[0] */
|
|
|
|
len = strnlen(argv[0], len) + 1;
|
|
|
|
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
*sz = len;
|
|
|
|
free(argv);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*sz < len)
|
|
|
|
{
|
|
|
|
free(argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(p, 0, len);
|
|
|
|
memcpy(p, argv[0], len);
|
|
|
|
free(argv);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-06 18:16:58 -08:00
|
|
|
const char * rust_current_exe()
|
2015-01-16 23:51:04 -08:00
|
|
|
{
|
|
|
|
static char *self = NULL;
|
|
|
|
char *argv0;
|
|
|
|
char **paths;
|
|
|
|
size_t sz;
|
|
|
|
int i;
|
Reduce the reliance on `PATH_MAX`
- Rewrite `std::sys::fs::readlink` not to rely on `PATH_MAX`
It currently has the following problems:
1. It uses `_PC_NAME_MAX` to query the maximum length of a file path in
the underlying system. However, the meaning of the constant is the
maximum length of *a path component*, not a full path. The correct
constant should be `_PC_PATH_MAX`.
2. `pathconf` *may* fail if the referred file does not exist. This can
be problematic if the file which the symbolic link points to does not
exist, but the link itself does exist. In this case, the current
implementation resorts to the hard-coded value of `1024`, which is not
ideal.
3. There may exist a platform where there is no limit on file path
lengths in general. That's the reaon why GNU Hurd doesn't define
`PATH_MAX` at all, in addition to having `pathconf` always returning
`-1`. In these platforms, the content of the symbolic link can be
silently truncated if the length exceeds the hard-coded limit mentioned
above.
4. The value obtained by `pathconf` may be outdated at the point of
actually calling `readlink`. This is inherently racy.
This commit introduces a loop that gradually increases the length of the
buffer passed to `readlink`, eliminating the need of `pathconf`.
- Remove the arbitrary memory limit of `std::sys::fs::realpath`
As per POSIX 2013, `realpath` will return a malloc'ed buffer if the
second argument is a null pointer.[1]
[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html
- Comment on functions that are still using `PATH_MAX`
There are some functions that only work in terms of `PATH_MAX`, such as
`F_GETPATH` in OS X. Comments on them for posterity.
2015-08-19 13:11:40 +09:00
|
|
|
/* If `PATH_MAX` is defined on the platform, `realpath` will truncate the
|
|
|
|
* resolved path up to `PATH_MAX`. While this can make the resolution fail if
|
|
|
|
* the executable is placed in a deep path, the usage of a buffer whose
|
|
|
|
* length depends on `PATH_MAX` is still memory safe. */
|
|
|
|
char buf[2*PATH_MAX], exe[PATH_MAX];
|
2015-01-16 23:51:04 -08:00
|
|
|
|
|
|
|
if (self != NULL)
|
|
|
|
return self;
|
|
|
|
|
|
|
|
if (rust_get_argv_zero(NULL, &sz) == -1)
|
|
|
|
return NULL;
|
|
|
|
if ((argv0 = calloc(sz, sizeof(char))) == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (rust_get_argv_zero(argv0, &sz) == -1)
|
|
|
|
{
|
|
|
|
free(argv0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if argv0 is a relative or absolute path, resolve it with realpath */
|
|
|
|
if ((*argv0 == '.') || (*argv0 == '/') || (strstr(argv0, "/") != NULL))
|
|
|
|
{
|
|
|
|
self = realpath(argv0, NULL);
|
|
|
|
free(argv0);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the path array */
|
|
|
|
if (rust_get_path_array(NULL, &sz) == -1)
|
|
|
|
{
|
|
|
|
free(argv0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if ((paths = calloc(sz, sizeof(char))) == NULL)
|
|
|
|
{
|
|
|
|
free(argv0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (rust_get_path_array(paths, &sz) == -1)
|
|
|
|
{
|
|
|
|
free(argv0);
|
|
|
|
free(paths);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; paths[i] != NULL; i++)
|
|
|
|
{
|
|
|
|
snprintf(buf, 2*PATH_MAX, "%s/%s", paths[i], argv0);
|
|
|
|
if (realpath(buf, exe) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (access(exe, F_OK | X_OK) == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
self = strdup(exe);
|
|
|
|
free(argv0);
|
|
|
|
free(paths);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(argv0);
|
|
|
|
free(paths);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__OpenBSD__)
|
|
|
|
|
2015-01-29 08:19:28 +01:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
2015-02-05 15:24:17 +01:00
|
|
|
const char * rust_current_exe() {
|
2015-01-29 08:19:28 +01:00
|
|
|
static char *self = NULL;
|
|
|
|
|
|
|
|
if (self == NULL) {
|
|
|
|
int mib[4];
|
|
|
|
char **argv = NULL;
|
|
|
|
size_t argv_len;
|
|
|
|
|
|
|
|
/* initialize mib */
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
mib[1] = KERN_PROC_ARGS;
|
|
|
|
mib[2] = getpid();
|
|
|
|
mib[3] = KERN_PROC_ARGV;
|
|
|
|
|
|
|
|
/* request KERN_PROC_ARGV size */
|
|
|
|
argv_len = 0;
|
|
|
|
if (sysctl(mib, 4, NULL, &argv_len, NULL, 0) == -1)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
/* allocate size */
|
|
|
|
if ((argv = malloc(argv_len)) == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
/* request KERN_PROC_ARGV */
|
|
|
|
if (sysctl(mib, 4, argv, &argv_len, NULL, 0) == -1) {
|
|
|
|
free(argv);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get realpath if possible */
|
|
|
|
if ((argv[0] != NULL) && ((*argv[0] == '.') || (*argv[0] == '/')
|
2015-02-05 14:38:56 -08:00
|
|
|
|| (strstr(argv[0], "/") != NULL)))
|
2015-01-29 08:19:28 +01:00
|
|
|
|
|
|
|
self = realpath(argv[0], NULL);
|
|
|
|
else
|
|
|
|
self = NULL;
|
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
free(argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (self);
|
|
|
|
}
|
2015-01-16 23:51:04 -08:00
|
|
|
|
2015-01-29 08:19:28 +01:00
|
|
|
#endif
|
|
|
|
|
2015-06-30 21:55:00 -07:00
|
|
|
#endif // !defined(_WIN32)
|
|
|
|
|
2010-06-23 21:03:09 -07:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: C++
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|