/src/gdal/port/cpl_getexecpath.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * Project: CPL - Common Portability Library |
4 | | * Purpose: Implement CPLGetExecPath(). |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ********************************************************************** |
8 | | * Copyright (c) 2005, Frank Warmerdam |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_port.h" |
14 | | #include "cpl_conv.h" |
15 | | |
16 | | #if HAVE_UNISTD_H |
17 | | #include <unistd.h> |
18 | | #endif |
19 | | |
20 | | #include "cpl_multiproc.h" |
21 | | #include "cpl_string.h" |
22 | | |
23 | | #if defined(_WIN32) |
24 | | #include <windows.h> |
25 | | #elif defined(__MACH__) && defined(__APPLE__) |
26 | | #include <mach-o/dyld.h> |
27 | | #elif defined(__FreeBSD__) || defined(__NetBSD__) |
28 | | #include <sys/sysctl.h> |
29 | | #include <sys/types.h> |
30 | | #endif |
31 | | |
32 | | /************************************************************************/ |
33 | | /* CPLGetExecPath() */ |
34 | | /************************************************************************/ |
35 | | |
36 | | /** |
37 | | * Fetch path of executable. |
38 | | * |
39 | | * The path to the executable currently running is returned. This path |
40 | | * includes the name of the executable. Currently this only works on |
41 | | * Windows, Linux, MacOS, FreeBSD and netBSD platforms. The returned path is UTF-8 |
42 | | * encoded, and will be nul-terminated if success is reported. |
43 | | * |
44 | | * @param pszPathBuf the buffer into which the path is placed. |
45 | | * @param nMaxLength the buffer size (including the nul-terminating character). |
46 | | * MAX_PATH+1 is suggested. |
47 | | * |
48 | | * @return FALSE on failure or TRUE on success. |
49 | | */ |
50 | | |
51 | | int CPLGetExecPath(char *pszPathBuf, int nMaxLength) |
52 | 0 | { |
53 | 0 | if (nMaxLength == 0) |
54 | 0 | return FALSE; |
55 | 0 | pszPathBuf[0] = '\0'; |
56 | |
|
57 | | #if defined(_WIN32) |
58 | | if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"))) |
59 | | { |
60 | | wchar_t *pwszPathBuf = |
61 | | static_cast<wchar_t *>(CPLCalloc(nMaxLength + 1, sizeof(wchar_t))); |
62 | | |
63 | | if (GetModuleFileNameW(nullptr, pwszPathBuf, nMaxLength) == 0) |
64 | | { |
65 | | CPLFree(pwszPathBuf); |
66 | | return FALSE; |
67 | | } |
68 | | else |
69 | | { |
70 | | char *pszDecoded = |
71 | | CPLRecodeFromWChar(pwszPathBuf, CPL_ENC_UCS2, CPL_ENC_UTF8); |
72 | | |
73 | | const size_t nStrlenDecoded = strlen(pszDecoded); |
74 | | strncpy(pszPathBuf, pszDecoded, nMaxLength); |
75 | | int bOK = TRUE; |
76 | | if (nStrlenDecoded >= static_cast<size_t>(nMaxLength) - 1) |
77 | | { |
78 | | pszPathBuf[nMaxLength - 1] = '\0'; |
79 | | // There is no easy way to detect if the string has been |
80 | | // truncated other than testing the existence of the file. |
81 | | VSIStatBufL sStat; |
82 | | bOK = (VSIStatL(pszPathBuf, &sStat) == 0); |
83 | | } |
84 | | CPLFree(pszDecoded); |
85 | | CPLFree(pwszPathBuf); |
86 | | return bOK; |
87 | | } |
88 | | } |
89 | | else |
90 | | { |
91 | | if (GetModuleFileNameA(nullptr, pszPathBuf, nMaxLength) == 0) |
92 | | return FALSE; |
93 | | else |
94 | | { |
95 | | const size_t nStrlenDecoded = strlen(pszPathBuf); |
96 | | int bOK = TRUE; |
97 | | if (nStrlenDecoded >= static_cast<size_t>(nMaxLength) - 1) |
98 | | { |
99 | | pszPathBuf[nMaxLength - 1] = '\0'; |
100 | | // There is no easy way to detect if the string has been |
101 | | // truncated other than testing the existence of the file. |
102 | | VSIStatBufL sStat; |
103 | | bOK = (VSIStatL(pszPathBuf, &sStat) == 0); |
104 | | } |
105 | | return bOK; |
106 | | } |
107 | | } |
108 | | #elif defined(__linux) |
109 | | long nPID = getpid(); |
110 | 0 | CPLString osExeLink; |
111 | |
|
112 | 0 | osExeLink.Printf("/proc/%ld/exe", nPID); |
113 | 0 | ssize_t nResultLen = readlink(osExeLink, pszPathBuf, nMaxLength); |
114 | 0 | if (nResultLen == nMaxLength) |
115 | 0 | pszPathBuf[nMaxLength - 1] = '\0'; |
116 | 0 | else if (nResultLen >= 0) |
117 | 0 | pszPathBuf[nResultLen] = '\0'; |
118 | |
|
119 | 0 | return nResultLen > 0 && nResultLen < nMaxLength; |
120 | | #elif defined(__MACH__) && defined(__APPLE__) |
121 | | uint32_t size = static_cast<uint32_t>(nMaxLength); |
122 | | if (_NSGetExecutablePath(pszPathBuf, &size) == 0) |
123 | | { |
124 | | return TRUE; |
125 | | } |
126 | | return FALSE; |
127 | | #elif defined(__FreeBSD__) |
128 | | int mib[4]; |
129 | | mib[0] = CTL_KERN; |
130 | | mib[1] = KERN_PROC; |
131 | | mib[2] = KERN_PROC_PATHNAME; |
132 | | mib[3] = -1; |
133 | | size_t size = static_cast<size_t>(nMaxLength); |
134 | | if (sysctl(mib, 4, pszPathBuf, &size, nullptr, 0) == 0) |
135 | | { |
136 | | return TRUE; |
137 | | } |
138 | | return FALSE; |
139 | | #elif defined(__NetBSD__) |
140 | | int mib[4]; |
141 | | mib[0] = CTL_KERN; |
142 | | mib[1] = KERN_PROC_ARGS; |
143 | | mib[2] = -1; |
144 | | mib[3] = KERN_PROC_PATHNAME; |
145 | | size_t size = static_cast<size_t>(nMaxLength); |
146 | | if (sysctl(mib, 4, pszPathBuf, &size, nullptr, 0) == 0) |
147 | | { |
148 | | return TRUE; |
149 | | } |
150 | | return FALSE; |
151 | | #else |
152 | | return FALSE; |
153 | | #endif |
154 | 0 | } |