1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
/****************************************************************************
**
** This file is part of GAP, a system for computational discrete algebra.
**
** Copyright of GAP belongs to its developers, whose names are too numerous
** to list here. Please refer to the COPYRIGHT file for details.
**
** SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "common.h"
#include "sysfiles.h"
#include "sysroots.h"
#include "sysstr.h"
#include "system.h"
#ifdef HPCGAP
#include "hpc/thread.h"
#endif
#include "config.h"
#include <stdlib.h> // for getenv, realpath, ...
#include <string.h> // for snprintf
#include <unistd.h> // for access, readlink, ...
#if defined(__APPLE__) && defined(__MACH__)
// Workaround: TRUE / FALSE are also defined by the macOS Mach-O headers
#define ENUM_DYLD_BOOL
#include <mach-o/dyld.h>
#endif
extern int realmain(int argc, const char * argv[]);
/****************************************************************************
**
*F * * * * * * * * * * finding location of executable * * * * * * * * * * * *
*/
#ifdef SYS_DEFAULT_PATHS
static void SetupInitialGapRoot(const char * argv0)
{
gap_strlcpy(SyDefaultRootPath, SYS_DEFAULT_PATHS, sizeof(SyDefaultRootPath));
}
#else
/****************************************************************************
**
** The function 'find_yourself' is based on code (C) 2015 Mark Whitis, under
** the MIT License : https://stackoverflow.com/a/34271901/928031
*/
static void
find_yourself(const char * argv0, char * result, size_t resultsize)
{
GAP_ASSERT(resultsize >= GAP_PATH_MAX);
char tmpbuf[GAP_PATH_MAX];
// absolute path, like '/usr/bin/gap'
if (argv0[0] == '/') {
if (realpath(argv0, result) && !access(result, F_OK)) {
return; // success
}
}
// relative path, like 'bin/gap.sh'
else if (strchr(argv0, '/')) {
if (!getcwd(tmpbuf, sizeof(tmpbuf)))
return;
gap_strlcat(tmpbuf, "/", sizeof(tmpbuf));
gap_strlcat(tmpbuf, argv0, sizeof(tmpbuf));
if (realpath(tmpbuf, result) && !access(result, F_OK)) {
return; // success
}
}
// executable name, like 'gap'
else {
char pathenv[GAP_PATH_MAX], *saveptr, *pathitem;
gap_strlcpy(pathenv, getenv("PATH"), sizeof(pathenv));
pathitem = strtok_r(pathenv, ":", &saveptr);
for (; pathitem; pathitem = strtok_r(NULL, ":", &saveptr)) {
gap_strlcpy(tmpbuf, pathitem, sizeof(tmpbuf));
gap_strlcat(tmpbuf, "/", sizeof(tmpbuf));
gap_strlcat(tmpbuf, argv0, sizeof(tmpbuf));
if (realpath(tmpbuf, result) && !access(result, F_OK)) {
return; // success
}
}
}
*result = 0; // reset buffer after error
}
static void SetupGAPLocation(const char * argv0, char * GAPExecLocation)
{
// In the code below, we keep resetting locBuf, as some of the methods we
// try do not promise to leave the buffer empty on a failed return.
char locBuf[GAP_PATH_MAX] = "";
Int4 length = 0;
#if defined(__APPLE__) && defined(__MACH__)
uint32_t len = sizeof(locBuf);
if (_NSGetExecutablePath(locBuf, &len) != 0) {
*locBuf = 0; // reset buffer after error
}
#endif
// try Linux procfs
if (!*locBuf) {
ssize_t ret = readlink("/proc/self/exe", locBuf, sizeof(locBuf));
if (ret < 0)
*locBuf = 0; // reset buffer after error
}
// try FreeBSD / DragonFly BSD procfs
if (!*locBuf) {
ssize_t ret = readlink("/proc/curproc/file", locBuf, sizeof(locBuf));
if (ret < 0)
*locBuf = 0; // reset buffer after error
}
// try NetBSD procfs
if (!*locBuf) {
ssize_t ret = readlink("/proc/curproc/exe", locBuf, sizeof(locBuf));
if (ret < 0)
*locBuf = 0; // reset buffer after error
}
// if we are still failing, go and search the path
if (!*locBuf) {
find_yourself(argv0, locBuf, GAP_PATH_MAX);
}
// resolve symlinks (if present)
if (!realpath(locBuf, GAPExecLocation))
*GAPExecLocation = 0; // reset buffer after error
// now strip the executable name off
length = strlen(GAPExecLocation);
while (length > 0 && GAPExecLocation[length] != '/') {
GAPExecLocation[length] = 0;
length--;
}
}
/****************************************************************************
**
*F SySetInitialGapRootPaths( <string> ) . . . . . set the root directories
**
** Set up GAP's initial root paths, based on the location of the
** GAP executable.
*/
static void SySetInitialGapRootPaths(const char * GAPExecLocation)
{
if (GAPExecLocation[0] != 0) {
// GAPExecLocation might be a subdirectory of GAP root,
// so we will go and search for the true GAP root.
// We try stepping back up to two levels.
char pathbuf[GAP_PATH_MAX];
char initgbuf[GAP_PATH_MAX];
strxcpy(pathbuf, GAPExecLocation, sizeof(pathbuf));
for (Int i = 0; i < 3; ++i) {
strxcpy(initgbuf, pathbuf, sizeof(initgbuf));
strxcat(initgbuf, "lib/init.g", sizeof(initgbuf));
if (SyIsReadableFile(initgbuf) == 0) {
gap_strlcpy(SyDefaultRootPath, pathbuf, sizeof(SyDefaultRootPath));
// escape from loop
return;
}
// try up a directory level
strxcat(pathbuf, "../", sizeof(pathbuf));
}
}
}
static void SetupInitialGapRoot(const char * argv0)
{
char GAPExecLocation[GAP_PATH_MAX] = "";
SetupGAPLocation(argv0, GAPExecLocation);
SySetInitialGapRootPaths(GAPExecLocation);
}
#endif
int main(int argc, const char * argv[])
{
InstallBacktraceHandlers();
SetupInitialGapRoot(argv[0]);
#ifdef HPCGAP
RunThreadedMain(realmain, argc, argv);
return 0;
#else
return realmain(argc, argv);
#endif
}
|