Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}