Merge pull request #969 from pwpiwi/gcc10_fixes
[legacy-proxmark3.git] / client / whereami.c
blob28277584eb1a7f474f135f9438fe821ebfd6415a
1 // (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
2 // https://github.com/gpakosz/whereami
4 // in case you want to #include "whereami.c" in a larger compilation unit
5 #if !defined(WHEREAMI_H)
6 #include <whereami.h>
7 #endif
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
13 #if defined(__linux__)
14 // make realpath() available:
15 #define _DEFAULT_SOURCE
16 #endif
18 #if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
19 #include <stdlib.h>
20 #endif
22 #if !defined(WAI_MALLOC)
23 #define WAI_MALLOC(size) malloc(size)
24 #endif
26 #if !defined(WAI_FREE)
27 #define WAI_FREE(p) free(p)
28 #endif
30 #if !defined(WAI_REALLOC)
31 #define WAI_REALLOC(p, size) realloc(p, size)
32 #endif
34 #ifndef WAI_NOINLINE
35 #if defined(_MSC_VER)
36 #define WAI_NOINLINE __declspec(noinline)
37 #elif defined(__GNUC__)
38 #define WAI_NOINLINE __attribute__((noinline))
39 #else
40 #error unsupported compiler
41 #endif
42 #endif
44 #if defined(_MSC_VER)
45 #define WAI_RETURN_ADDRESS() _ReturnAddress()
46 #elif defined(__GNUC__)
47 #define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
48 #else
49 #error unsupported compiler
50 #endif
52 #if defined(_WIN32)
54 #define WIN32_LEAN_AND_MEAN
55 #if defined(_MSC_VER)
56 #pragma warning(push, 3)
57 #endif
58 #include <windows.h>
59 //#include <intrin.h> // not required and doesn't exist in old mingw environments
60 #if defined(_MSC_VER)
61 #pragma warning(pop)
62 #endif
64 static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
66 wchar_t buffer1[MAX_PATH];
67 wchar_t buffer2[MAX_PATH];
68 wchar_t* path = NULL;
69 int length = -1;
71 for (;;)
73 DWORD size;
74 int length_, length__;
76 size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0]));
78 if (size == 0)
79 break;
80 else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0])))
82 DWORD size_ = size;
85 wchar_t* path_;
87 path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2);
88 if (!path_)
89 break;
90 size_ *= 2;
91 path = path_;
92 size = GetModuleFileNameW(module, path, size_);
94 while (size == size_);
96 if (size == size_)
97 break;
99 else
100 path = buffer1;
102 if (!_wfullpath(buffer2, path, MAX_PATH))
103 break;
104 length_ = (int)wcslen(buffer2);
105 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_ , out, capacity, NULL, NULL);
107 if (length__ == 0)
108 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL);
109 if (length__ == 0)
110 break;
112 if (length__ <= capacity && dirname_length)
114 int i;
116 for (i = length__ - 1; i >= 0; --i)
118 if (out[i] == '\\')
120 *dirname_length = i;
121 break;
126 length = length__;
128 break;
131 if (path != buffer1)
132 WAI_FREE(path);
134 return length;
137 WAI_NOINLINE
138 WAI_FUNCSPEC
139 int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
141 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
144 // GetModuleHandleEx() is not available on old mingw environments. We don't need getModulePath() yet.
145 // Sacrifice it for the time being to improve backwards compatibility
146 /* WAI_NOINLINE
147 WAI_FUNCSPEC
148 int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
150 HMODULE module;
151 int length = -1;
153 #if defined(_MSC_VER)
154 #pragma warning(push)
155 #pragma warning(disable: 4054)
156 #endif
157 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
158 #if defined(_MSC_VER)
159 #pragma warning(pop)
160 #endif
162 length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
165 return length;
169 #elif defined(__linux__)
171 #include <stdio.h>
172 #include <stdlib.h>
173 #include <string.h>
174 // #include <limits.h> // not all linux distributions define PATH_MAX in limits.h because it depends on the filesystem. Therefore use...
175 #include <linux/limits.h>
176 #ifndef __STDC_FORMAT_MACROS
177 #define __STDC_FORMAT_MACROS
178 #endif
179 #include <inttypes.h>
181 #if !defined(WAI_PROC_SELF_EXE)
182 #define WAI_PROC_SELF_EXE "/proc/self/exe"
183 #endif
185 WAI_FUNCSPEC
186 int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
188 char buffer[PATH_MAX];
189 char* resolved = NULL;
190 int length = -1;
192 for (;;)
194 resolved = realpath(WAI_PROC_SELF_EXE, buffer);
195 if (!resolved)
196 break;
198 length = (int)strlen(resolved);
199 if (length <= capacity)
201 memcpy(out, resolved, length);
203 if (dirname_length)
205 int i;
207 for (i = length - 1; i >= 0; --i)
209 if (out[i] == '/')
211 *dirname_length = i;
212 break;
218 break;
221 return length;
224 #if !defined(WAI_PROC_SELF_MAPS_RETRY)
225 #define WAI_PROC_SELF_MAPS_RETRY 5
226 #endif
228 #if !defined(WAI_PROC_SELF_MAPS)
229 #define WAI_PROC_SELF_MAPS "/proc/self/maps"
230 #endif
232 #if defined(__ANDROID__) || defined(ANDROID)
233 #include <fcntl.h>
234 #include <sys/mman.h>
235 #endif
237 WAI_NOINLINE
238 WAI_FUNCSPEC
239 int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
241 int length = -1;
242 FILE* maps = NULL;
243 int i;
245 for (i = 0; i < WAI_PROC_SELF_MAPS_RETRY; ++i)
247 maps = fopen(WAI_PROC_SELF_MAPS, "r");
248 if (!maps)
249 break;
251 for (;;)
253 char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
254 uint64_t low, high;
255 char perms[5];
256 uint64_t offset;
257 uint32_t major, minor;
258 char path[PATH_MAX];
259 uint32_t inode;
261 if (!fgets(buffer, sizeof(buffer), maps))
262 break;
264 if (sscanf(buffer, "%" SCNx64 "-%" SCNx64 " %s %" SCNx64 " %" SCNx32 ":%" SCNx32 " %" SCNu32 " %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
266 uint64_t addr = (uint64_t)(uintptr_t)WAI_RETURN_ADDRESS();
267 if (low <= addr && addr <= high)
269 char* resolved;
271 resolved = realpath(path, buffer);
272 if (!resolved)
273 break;
275 length = (int)strlen(resolved);
276 #if defined(__ANDROID__) || defined(ANDROID)
277 if (length > 4
278 &&buffer[length - 1] == 'k'
279 &&buffer[length - 2] == 'p'
280 &&buffer[length - 3] == 'a'
281 &&buffer[length - 4] == '.')
283 int fd = open(path, O_RDONLY);
284 char* begin;
285 char* p;
287 begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
288 p = begin + offset;
290 while (p >= begin) // scan backwards
292 if (*((uint32_t*)p) == 0x04034b50UL) // local file header found
294 uint16_t length_ = *((uint16_t*)(p + 26));
296 if (length + 2 + length_ < (int)sizeof(buffer))
298 memcpy(&buffer[length], "!/", 2);
299 memcpy(&buffer[length + 2], p + 30, length_);
300 length += 2 + length_;
303 break;
306 p -= 4;
309 munmap(begin, offset);
310 close(fd);
312 #endif
313 if (length <= capacity)
315 memcpy(out, resolved, length);
317 if (dirname_length)
319 int i;
321 for (i = length - 1; i >= 0; --i)
323 if (out[i] == '/')
325 *dirname_length = i;
326 break;
332 break;
337 fclose(maps);
339 if (length != -1)
340 break;
343 return length;
346 #elif defined(__APPLE__)
348 #define _DARWIN_BETTER_REALPATH
349 #include <mach-o/dyld.h>
350 #include <limits.h>
351 #include <stdlib.h>
352 #include <string.h>
353 #include <dlfcn.h>
355 WAI_FUNCSPEC
356 int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
358 char buffer1[PATH_MAX];
359 char buffer2[PATH_MAX];
360 char* path = buffer1;
361 char* resolved = NULL;
362 int length = -1;
364 for (;;)
366 uint32_t size = (uint32_t)sizeof(buffer1);
367 if (_NSGetExecutablePath(path, &size) == -1)
369 path = (char*)WAI_MALLOC(size);
370 if (!_NSGetExecutablePath(path, &size))
371 break;
374 resolved = realpath(path, buffer2);
375 if (!resolved)
376 break;
378 length = (int)strlen(resolved);
379 if (length <= capacity)
381 memcpy(out, resolved, length);
383 if (dirname_length)
385 int i;
387 for (i = length - 1; i >= 0; --i)
389 if (out[i] == '/')
391 *dirname_length = i;
392 break;
398 break;
401 if (path != buffer1)
402 WAI_FREE(path);
404 return length;
407 WAI_NOINLINE
408 WAI_FUNCSPEC
409 int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
411 char buffer[PATH_MAX];
412 char* resolved = NULL;
413 int length = -1;
415 for(;;)
417 Dl_info info;
419 if (dladdr(WAI_RETURN_ADDRESS(), &info))
421 resolved = realpath(info.dli_fname, buffer);
422 if (!resolved)
423 break;
425 length = (int)strlen(resolved);
426 if (length <= capacity)
428 memcpy(out, resolved, length);
430 if (dirname_length)
432 int i;
434 for (i = length - 1; i >= 0; --i)
436 if (out[i] == '/')
438 *dirname_length = i;
439 break;
446 break;
449 return length;
452 #elif defined(__QNXNTO__)
454 #include <limits.h>
455 #include <stdio.h>
456 #include <stdlib.h>
457 #include <string.h>
458 #include <dlfcn.h>
460 #if !defined(WAI_PROC_SELF_EXE)
461 #define WAI_PROC_SELF_EXE "/proc/self/exefile"
462 #endif
464 WAI_FUNCSPEC
465 int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
467 char buffer1[PATH_MAX];
468 char buffer2[PATH_MAX];
469 char* resolved = NULL;
470 FILE* self_exe = NULL;
471 int length = -1;
473 for (;;)
475 self_exe = fopen(WAI_PROC_SELF_EXE, "r");
476 if (!self_exe)
477 break;
479 if (!fgets(buffer1, sizeof(buffer1), self_exe))
480 break;
482 resolved = realpath(buffer1, buffer2);
483 if (!resolved)
484 break;
486 length = (int)strlen(resolved);
487 if (length <= capacity)
489 memcpy(out, resolved, length);
491 if (dirname_length)
493 int i;
495 for (i = length - 1; i >= 0; --i)
497 if (out[i] == '/')
499 *dirname_length = i;
500 break;
506 break;
509 fclose(self_exe);
511 return length;
514 WAI_FUNCSPEC
515 int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
517 char buffer[PATH_MAX];
518 char* resolved = NULL;
519 int length = -1;
521 for(;;)
523 Dl_info info;
525 if (dladdr(WAI_RETURN_ADDRESS(), &info))
527 resolved = realpath(info.dli_fname, buffer);
528 if (!resolved)
529 break;
531 length = (int)strlen(resolved);
532 if (length <= capacity)
534 memcpy(out, resolved, length);
536 if (dirname_length)
538 int i;
540 for (i = length - 1; i >= 0; --i)
542 if (out[i] == '/')
544 *dirname_length = i;
545 break;
552 break;
555 return length;
558 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
559 defined(__FreeBSD_kernel__) || defined(__NetBSD__)
561 #include <limits.h>
562 #include <stdlib.h>
563 #include <string.h>
564 #include <sys/types.h>
565 #include <sys/sysctl.h>
566 #include <dlfcn.h>
568 WAI_FUNCSPEC
569 int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
571 char buffer1[PATH_MAX];
572 char buffer2[PATH_MAX];
573 char* path = buffer1;
574 char* resolved = NULL;
575 int length = -1;
577 for (;;)
579 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
580 size_t size = sizeof(buffer1);
582 if (sysctl(mib, (u_int)(sizeof(mib) / sizeof(mib[0])), path, &size, NULL, 0) != 0)
583 break;
585 resolved = realpath(path, buffer2);
586 if (!resolved)
587 break;
589 length = (int)strlen(resolved);
590 if (length <= capacity)
592 memcpy(out, resolved, length);
594 if (dirname_length)
596 int i;
598 for (i = length - 1; i >= 0; --i)
600 if (out[i] == '/')
602 *dirname_length = i;
603 break;
609 break;
612 if (path != buffer1)
613 WAI_FREE(path);
615 return length;
618 WAI_NOINLINE
619 WAI_FUNCSPEC
620 int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
622 char buffer[PATH_MAX];
623 char* resolved = NULL;
624 int length = -1;
626 for(;;)
628 Dl_info info;
630 if (dladdr(WAI_RETURN_ADDRESS(), &info))
632 resolved = realpath(info.dli_fname, buffer);
633 if (!resolved)
634 break;
636 length = (int)strlen(resolved);
637 if (length <= capacity)
639 memcpy(out, resolved, length);
641 if (dirname_length)
643 int i;
645 for (i = length - 1; i >= 0; --i)
647 if (out[i] == '/')
649 *dirname_length = i;
650 break;
657 break;
660 return length;
663 #else
665 #error unsupported platform
667 #endif
669 #ifdef __cplusplus
671 #endif