Line data Source code
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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_port.h"
30 : #include "cpl_conv.h"
31 :
32 : #if HAVE_UNISTD_H
33 : #include <unistd.h>
34 : #endif
35 :
36 : #include "cpl_multiproc.h"
37 : #include "cpl_string.h"
38 :
39 : #if defined(_WIN32)
40 : #include <windows.h>
41 : #elif defined(__MACH__) && defined(__APPLE__)
42 : #include <mach-o/dyld.h>
43 : #elif defined(__FreeBSD__)
44 : #include <sys/sysctl.h>
45 : #include <sys/types.h>
46 : #endif
47 :
48 : /************************************************************************/
49 : /* CPLGetExecPath() */
50 : /************************************************************************/
51 :
52 : /**
53 : * Fetch path of executable.
54 : *
55 : * The path to the executable currently running is returned. This path
56 : * includes the name of the executable. Currently this only works on
57 : * Windows, Linux, MacOS and FreeBSD platforms. The returned path is UTF-8
58 : * encoded, and will be nul-terminated if success is reported.
59 : *
60 : * @param pszPathBuf the buffer into which the path is placed.
61 : * @param nMaxLength the buffer size (including the nul-terminating character).
62 : * MAX_PATH+1 is suggested.
63 : *
64 : * @return FALSE on failure or TRUE on success.
65 : */
66 :
67 135 : int CPLGetExecPath(char *pszPathBuf, int nMaxLength)
68 : {
69 135 : if (nMaxLength == 0)
70 0 : return FALSE;
71 135 : pszPathBuf[0] = '\0';
72 :
73 : #if defined(_WIN32)
74 : if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
75 : {
76 : wchar_t *pwszPathBuf =
77 : static_cast<wchar_t *>(CPLCalloc(nMaxLength + 1, sizeof(wchar_t)));
78 :
79 : if (GetModuleFileNameW(nullptr, pwszPathBuf, nMaxLength) == 0)
80 : {
81 : CPLFree(pwszPathBuf);
82 : return FALSE;
83 : }
84 : else
85 : {
86 : char *pszDecoded =
87 : CPLRecodeFromWChar(pwszPathBuf, CPL_ENC_UCS2, CPL_ENC_UTF8);
88 :
89 : const size_t nStrlenDecoded = strlen(pszDecoded);
90 : strncpy(pszPathBuf, pszDecoded, nMaxLength);
91 : int bOK = TRUE;
92 : if (nStrlenDecoded >= static_cast<size_t>(nMaxLength) - 1)
93 : {
94 : pszPathBuf[nMaxLength - 1] = '\0';
95 : // There is no easy way to detect if the string has been
96 : // truncated other than testing the existence of the file.
97 : VSIStatBufL sStat;
98 : bOK = (VSIStatL(pszPathBuf, &sStat) == 0);
99 : }
100 : CPLFree(pszDecoded);
101 : CPLFree(pwszPathBuf);
102 : return bOK;
103 : }
104 : }
105 : else
106 : {
107 : if (GetModuleFileNameA(nullptr, pszPathBuf, nMaxLength) == 0)
108 : return FALSE;
109 : else
110 : {
111 : const size_t nStrlenDecoded = strlen(pszPathBuf);
112 : int bOK = TRUE;
113 : if (nStrlenDecoded >= static_cast<size_t>(nMaxLength) - 1)
114 : {
115 : pszPathBuf[nMaxLength - 1] = '\0';
116 : // There is no easy way to detect if the string has been
117 : // truncated other than testing the existence of the file.
118 : VSIStatBufL sStat;
119 : bOK = (VSIStatL(pszPathBuf, &sStat) == 0);
120 : }
121 : return bOK;
122 : }
123 : }
124 : #elif defined(__linux)
125 135 : long nPID = getpid();
126 135 : CPLString osExeLink;
127 :
128 135 : osExeLink.Printf("/proc/%ld/exe", nPID);
129 135 : ssize_t nResultLen = readlink(osExeLink, pszPathBuf, nMaxLength);
130 135 : if (nResultLen == nMaxLength)
131 1 : pszPathBuf[nMaxLength - 1] = '\0';
132 134 : else if (nResultLen >= 0)
133 134 : pszPathBuf[nResultLen] = '\0';
134 :
135 135 : return nResultLen > 0 && nResultLen < nMaxLength;
136 : #elif defined(__MACH__) && defined(__APPLE__)
137 : uint32_t size = static_cast<uint32_t>(nMaxLength);
138 : if (_NSGetExecutablePath(pszPathBuf, &size) == 0)
139 : {
140 : return TRUE;
141 : }
142 : return FALSE;
143 : #elif defined(__FreeBSD__)
144 : int mib[4];
145 : mib[0] = CTL_KERN;
146 : mib[1] = KERN_PROC;
147 : mib[2] = KERN_PROC_PATHNAME;
148 : mib[3] = -1;
149 : size_t size = static_cast<size_t>(nMaxLength);
150 : if (sysctl(mib, 4, pszPathBuf, &size, nullptr, 0) == 0)
151 : {
152 : return TRUE;
153 : }
154 : return FALSE;
155 : #else
156 : return FALSE;
157 : #endif
158 : }
|