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 : * 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__) 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 and FreeBSD 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 129 : int CPLGetExecPath(char *pszPathBuf, int nMaxLength) 52 : { 53 129 : if (nMaxLength == 0) 54 0 : return FALSE; 55 129 : 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 129 : long nPID = getpid(); 110 129 : CPLString osExeLink; 111 : 112 129 : osExeLink.Printf("/proc/%ld/exe", nPID); 113 129 : ssize_t nResultLen = readlink(osExeLink, pszPathBuf, nMaxLength); 114 129 : if (nResultLen == nMaxLength) 115 1 : pszPathBuf[nMaxLength - 1] = '\0'; 116 128 : else if (nResultLen >= 0) 117 128 : pszPathBuf[nResultLen] = '\0'; 118 : 119 129 : 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 : #else 140 : return FALSE; 141 : #endif 142 : }