]> git.lizzy.rs Git - rust.git/blob - src/rt/rust_builtin.c
Rollup merge of #29062 - rgardner:rgardner-fix-book-comp-warning, r=alexcrichton
[rust.git] / src / rt / rust_builtin.c
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #if !defined(_WIN32)
12
13 #include <stdint.h>
14 #include <time.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <stdlib.h>
18
19
20 #include <dirent.h>
21 #include <pthread.h>
22 #include <signal.h>
23 #include <sys/stat.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #ifdef __APPLE__
29 #include <TargetConditionals.h>
30 #include <mach/mach_time.h>
31
32 #if !(TARGET_OS_IPHONE)
33 #include <crt_externs.h>
34 #endif
35 #endif
36
37 char*
38 rust_list_dir_val(struct dirent* entry_ptr) {
39     return entry_ptr->d_name;
40 }
41
42 // Android's struct dirent does have d_type from the very beginning
43 // (android-3). _DIRENT_HAVE_D_TYPE is not defined all the way to android-21
44 // though...
45 #if defined(__ANDROID__)
46 # define _DIRENT_HAVE_D_TYPE
47 #endif
48
49 int
50 rust_dir_get_mode(struct dirent* entry_ptr) {
51 #if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__)
52     switch (entry_ptr->d_type) {
53         case DT_BLK: return S_IFBLK;
54         case DT_CHR: return S_IFCHR;
55         case DT_FIFO: return S_IFIFO;
56         case DT_LNK: return S_IFLNK;
57         case DT_REG: return S_IFREG;
58         case DT_SOCK: return S_IFSOCK;
59         case DT_DIR: return S_IFDIR;
60     }
61 #endif
62     return -1;
63 }
64
65 ino_t
66 rust_dir_get_ino(struct dirent* entry_ptr) {
67     return entry_ptr->d_ino;
68 }
69
70 DIR*
71 rust_opendir(char *dirname) {
72     return opendir(dirname);
73 }
74
75 int
76 rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
77     return readdir_r(dirp, entry, result);
78 }
79
80 int
81 rust_dirent_t_size() {
82     return sizeof(struct dirent);
83 }
84
85 #if defined(__BSD__)
86 static int
87 get_num_cpus() {
88     /* swiped from http://stackoverflow.com/questions/150355/
89        programmatically-find-the-number-of-cores-on-a-machine */
90
91     unsigned int numCPU;
92     int mib[4];
93     size_t len = sizeof(numCPU);
94
95     /* set the mib for hw.ncpu */
96     mib[0] = CTL_HW;
97     mib[1] = HW_AVAILCPU;  // alternatively, try HW_NCPU;
98
99     /* get the number of CPUs from the system */
100     sysctl(mib, 2, &numCPU, &len, NULL, 0);
101
102     if( numCPU < 1 ) {
103         mib[1] = HW_NCPU;
104         sysctl( mib, 2, &numCPU, &len, NULL, 0 );
105
106         if( numCPU < 1 ) {
107             numCPU = 1;
108         }
109     }
110     return numCPU;
111 }
112 #elif defined(__GNUC__)
113 static int
114 get_num_cpus() {
115     return sysconf(_SC_NPROCESSORS_ONLN);
116 }
117 #endif
118
119 uintptr_t
120 rust_get_num_cpus() {
121     return get_num_cpus();
122 }
123
124 #if defined(__DragonFly__)
125 #include <errno.h>
126 // In DragonFly __error() is an inline function and as such
127 // no symbol exists for it.
128 int *__dfly_error(void) { return __error(); }
129 #endif
130
131 #if defined(__Bitrig__)
132 #include <stdio.h>
133 #include <sys/param.h>
134 #include <sys/sysctl.h>
135 #include <limits.h>
136
137 int rust_get_path(void *p, size_t* sz)
138 {
139   int mib[4];
140   char *eq = NULL;
141   char *key = NULL;
142   char *val = NULL;
143   char **menv = NULL;
144   size_t maxlen, len;
145   int nenv = 0;
146   int i;
147
148   if ((p == NULL) && (sz == NULL))
149     return -1;
150
151   /* get the argv array */
152   mib[0] = CTL_KERN;
153   mib[1] = KERN_PROC_ARGS;
154   mib[2] = getpid();
155   mib[3] = KERN_PROC_ENV;
156
157   /* get the number of bytes needed to get the env */
158   maxlen = 0;
159   if (sysctl(mib, 4, NULL, &maxlen, NULL, 0) == -1)
160     return -1;
161
162   /* allocate the buffer */
163   if ((menv = calloc(maxlen, sizeof(char))) == NULL)
164     return -1;
165
166   /* get the env array */
167   if (sysctl(mib, 4, menv, &maxlen, NULL, 0) == -1)
168   {
169     free(menv);
170     return -1;
171   }
172
173   mib[3] = KERN_PROC_NENV;
174   len = sizeof(int);
175   /* get the length of env array */
176   if (sysctl(mib, 4, &nenv, &len, NULL, 0) == -1)
177   {
178     free(menv);
179     return -1;
180   }
181
182   /* find _ key and resolve the value */
183   for (i = 0; i < nenv; i++)
184   {
185     if ((eq = strstr(menv[i], "=")) == NULL)
186       continue;
187
188     key = menv[i];
189     val = eq + 1;
190     *eq = '\0';
191
192     if (strncmp(key, "PATH", maxlen) != 0)
193       continue;
194
195     if (p == NULL)
196     {
197       /* return the length of the value + NUL */
198       *sz = strnlen(val, maxlen) + 1;
199       free(menv);
200       return 0;
201     }
202     else
203     {
204       /* copy *sz bytes to the output buffer */
205       memcpy(p, val, *sz);
206       free(menv);
207       return 0;
208     }
209   }
210
211   free(menv);
212   return -1;
213 }
214
215 int rust_get_path_array(void * p, size_t * sz)
216 {
217   char *path, *str;
218   char **buf;
219   int i, num;
220   size_t len;
221
222   if ((p == NULL) && (sz == NULL))
223     return -1;
224
225   /* get the length of the PATH value */
226   if (rust_get_path(NULL, &len) == -1)
227     return -1;
228
229   if (len == 0)
230     return -1;
231
232   /* allocate the buffer */
233   if ((path = calloc(len, sizeof(char))) == NULL)
234     return -1;
235
236   /* get the PATH value */
237   if (rust_get_path(path, &len) == -1)
238   {
239     free(path);
240     return -1;
241   }
242
243   /* count the number of parts in the PATH */
244   num = 1;
245   for(str = path; *str != '\0'; str++)
246   {
247     if (*str == ':')
248       num++;
249   }
250
251   /* calculate the size of the buffer for the 2D array */
252   len = (num * sizeof(char*) + 1) + strlen(path) + 1;
253
254   if (p == NULL)
255   {
256     free(path);
257     *sz = len;
258     return 0;
259   }
260
261   /* make sure we have enough buffer space */
262   if (*sz < len)
263   {
264     free(path);
265     return -1;
266   }
267
268   /* zero out the buffer */
269   buf = (char**)p;
270   memset(buf, 0, *sz);
271
272   /* copy the data into the right place */
273   str = p + ((num+1) * sizeof(char*));
274   memcpy(str, path, strlen(path));
275
276   /* parse the path into it's parts */
277   for (i = 0; i < num && (buf[i] = strsep(&str, ":")) != NULL; i++) {;}
278   buf[num] = NULL;
279
280   free(path);
281   return 0;
282 }
283
284 int rust_get_argv_zero(void* p, size_t* sz)
285 {
286   int mib[4];
287   char **argv = NULL;
288   size_t len;
289
290   if ((p == NULL) && (sz == NULL))
291     return -1;
292
293   /* get the argv array */
294   mib[0] = CTL_KERN;
295   mib[1] = KERN_PROC_ARGS;
296   mib[2] = getpid();
297   mib[3] = KERN_PROC_ARGV;
298
299   /* request KERN_PROC_ARGV size */
300   len = 0;
301   if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1)
302     return -1;
303
304   /* allocate buffer to receive the values */
305   if ((argv = malloc(len)) == NULL)
306     return -1;
307
308   /* get the argv array */
309   if (sysctl(mib, 4, argv, &len, NULL, 0) == -1)
310   {
311     free(argv);
312     return -1;
313   }
314
315   /* get length of argv[0] */
316   len = strnlen(argv[0], len) + 1;
317
318   if (p == NULL)
319   {
320     *sz = len;
321     free(argv);
322     return 0;
323   }
324
325   if (*sz < len)
326   {
327     free(argv);
328     return -1;
329   }
330
331   memcpy(p, argv[0], len);
332   free(argv);
333   return 0;
334 }
335
336 const char * rust_current_exe()
337 {
338   static char *self = NULL;
339   char *argv0;
340   char **paths;
341   size_t sz;
342   int i;
343   /* If `PATH_MAX` is defined on the platform, `realpath` will truncate the
344    * resolved path up to `PATH_MAX`. While this can make the resolution fail if
345    * the executable is placed in a deep path, the usage of a buffer whose
346    * length depends on `PATH_MAX` is still memory safe. */
347   char buf[2*PATH_MAX], exe[PATH_MAX];
348
349   if (self != NULL)
350     return self;
351
352   if (rust_get_argv_zero(NULL, &sz) == -1)
353     return NULL;
354   if ((argv0 = calloc(sz, sizeof(char))) == NULL)
355     return NULL;
356   if (rust_get_argv_zero(argv0, &sz) == -1)
357   {
358     free(argv0);
359     return NULL;
360   }
361
362   /* if argv0 is a relative or absolute path, resolve it with realpath */
363   if ((*argv0 == '.') || (*argv0 == '/') || (strstr(argv0, "/") != NULL))
364   {
365     self = realpath(argv0, NULL);
366     free(argv0);
367     return self;
368   }
369
370   /* get the path array */
371   if (rust_get_path_array(NULL, &sz) == -1)
372   {
373     free(argv0);
374     return NULL;
375   }
376   if ((paths = calloc(sz, sizeof(char))) == NULL)
377   {
378     free(argv0);
379     return NULL;
380   }
381   if (rust_get_path_array(paths, &sz) == -1)
382   {
383     free(argv0);
384     free(paths);
385     return NULL;
386   }
387
388   for(i = 0; paths[i] != NULL; i++)
389   {
390     snprintf(buf, 2*PATH_MAX, "%s/%s", paths[i], argv0);
391     if (realpath(buf, exe) == NULL)
392       continue;
393
394     if (access(exe, F_OK | X_OK) == -1)
395       continue;
396
397     self = strdup(exe);
398     free(argv0);
399     free(paths);
400     return self;
401   }
402
403   free(argv0);
404   free(paths);
405   return NULL;
406 }
407
408 #elif defined(__OpenBSD__)
409
410 #include <sys/param.h>
411 #include <sys/sysctl.h>
412 #include <limits.h>
413
414 const char * rust_current_exe() {
415     static char *self = NULL;
416
417     if (self == NULL) {
418         int mib[4];
419         char **argv = NULL;
420         size_t argv_len;
421
422         /* initialize mib */
423         mib[0] = CTL_KERN;
424         mib[1] = KERN_PROC_ARGS;
425         mib[2] = getpid();
426         mib[3] = KERN_PROC_ARGV;
427
428         /* request KERN_PROC_ARGV size */
429         argv_len = 0;
430         if (sysctl(mib, 4, NULL, &argv_len, NULL, 0) == -1)
431             return (NULL);
432
433         /* allocate size */
434         if ((argv = malloc(argv_len)) == NULL)
435             return (NULL);
436
437         /* request KERN_PROC_ARGV */
438         if (sysctl(mib, 4, argv, &argv_len, NULL, 0) == -1) {
439             free(argv);
440             return (NULL);
441         }
442
443         /* get realpath if possible */
444         if ((argv[0] != NULL) && ((*argv[0] == '.') || (*argv[0] == '/')
445                                 || (strstr(argv[0], "/") != NULL)))
446
447             self = realpath(argv[0], NULL);
448         else
449             self = NULL;
450
451         /* cleanup */
452         free(argv);
453     }
454
455     return (self);
456 }
457
458 #endif
459
460 #endif // !defined(_WIN32)
461
462 //
463 // Local Variables:
464 // mode: C++
465 // fill-column: 78;
466 // indent-tabs-mode: nil
467 // c-basic-offset: 4
468 // buffer-file-coding-system: utf-8-unix
469 // End:
470 //