/*********************************************************************** * OSXCross Compiler Wrapper * * Copyright (C) 2014, 2015 by Thomas Poechtrager * * t.poechtrager@gmail.com * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***********************************************************************/ #include "compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #include #include #include #else #include #include #endif #ifdef __APPLE__ #include #include #include #include #include #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) #include #include #include #endif #ifdef __FreeBSD__ #include #endif #include "tools.h" namespace tools { // // Terminal text colors // bool isTerminal() { #ifndef _WIN32 static bool first = false; static bool val; if (!first) { val = !!isatty(fileno(stderr)); first = true; } return val; #else return false; #endif } // // Executable path // char *getExecutablePath(char *buf, size_t len) { char *p; #ifdef __APPLE__ unsigned int l = len; if (_NSGetExecutablePath(buf, &l) != 0) return nullptr; #elif defined(__FreeBSD__) || defined(__DragonFly__) int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; size_t l = len; if (sysctl(mib, 4, buf, &l, nullptr, 0) != 0) return nullptr; #elif defined(__OpenBSD__) int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; char **argv; size_t l; const char *comm; int ok = 0; if (sysctl(mib, 4, NULL, &l, NULL, 0) < 0) abort(); argv = new char *[l]; if (sysctl(mib, 4, argv, &l, NULL, 0) < 0) abort(); comm = argv[0]; if (*comm == '/' || *comm == '.') { char *rpath; if ((rpath = realpath(comm, NULL))) { strlcpy(buf, rpath, len); free(rpath); ok = 1; } } else { char *sp; char *xpath = strdup(getenv("PATH")); char *path = strtok_r(xpath, ":", &sp); struct stat st; if (!xpath) abort(); while (path) { snprintf(buf, len, "%s/%s", path, comm); if (!stat(buf, &st) && (st.st_mode & S_IXUSR)) { ok = 1; break; } path = strtok_r(NULL, ":", &sp); } free(xpath); } if (ok) l = strlen(buf); else l = 0; delete[] argv; #elif defined(_WIN32) size_t l = GetModuleFileName(nullptr, buf, (DWORD)len); #else ssize_t l = readlink("/proc/self/exe", buf, len); assert(l > 0 && "/proc not mounted?"); #endif if (l <= 0) return nullptr; buf[len - 1] = '\0'; p = strrchr(buf, PATHDIV); if (p) *p = '\0'; return buf; } const std::string &getParentProcessName() { static std::string name; #ifdef _WIN32 HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe; auto zerope = [&]() { memset(&pe, 0, sizeof(pe)); pe.dwSize = sizeof(PROCESSENTRY32); }; zerope(); auto pid = GetCurrentProcessId(); decltype(pid) ppid = -1; if (Process32First(h, &pe)) { do { if (pe.th32ProcessID == pid) { ppid = pe.th32ParentProcessID; break; } } while (Process32Next(h, &pe)); } if (ppid != static_cast(-1)) { PROCESSENTRY32 *ppe = nullptr; zerope(); if (Process32First(h, &pe)) { do { if (pe.th32ProcessID == ppid) { ppe = &pe; break; } } while (Process32Next(h, &pe)); } if (ppe) { char *p = strrchr(ppe->szExeFile, '\\'); if (p) { name = p + 1; } else { name = ppe->szExeFile; } } } CloseHandle(h); if (!name.empty()) { return name; } #else auto getName = [](const char * path)->const char * { if (const char *p = strrchr(path, '/')) { return p + 1; } return path; }; auto ppid = getppid(); #ifdef __APPLE__ char path[PROC_PIDPATHINFO_MAXSIZE]; if (proc_pidpath(ppid, path, sizeof(path))) { name = getName(path); return name; } #elif defined(__FreeBSD__) struct kinfo_proc *proc = kinfo_getproc(ppid); if (proc) { name = getName(proc->ki_comm); free(proc); return name; } #else std::stringstream file; file << "/proc/" << ppid << "/comm"; if (getFileContent(file.str(), name)) { if (!name.empty() && name.rbegin()[0] == '\n') { name.resize(name.size() - 1); } return name; } else { clear(file); file << "/proc/" << ppid << "/exe"; char buf[PATH_MAX + 1]; if (readlink(file.str().c_str(), buf, sizeof(buf)) > 0) { buf[PATH_MAX] = '\0'; name = getName(buf); return name; } } #endif #endif name = "unknown"; return name; } #ifdef _WIN32 std::string &fixPathDiv(std::string &path) { for (auto &c : path) { if (c == '/') c = '\\'; } return path; } #endif // // Environment // void concatEnvVariable(const char *var, const std::string &val) { std::string nval = val; if (char *oldval = getenv(var)) { nval += ":"; nval += oldval; } setenv(var, nval.c_str(), 1); } std::string &escapePath(const std::string &path, std::string &escapedpath) { for (const char *p = path.c_str(); *p; ++p) { switch (*p) { case '"': case '\'': case '\\': case '$': case '(': case ')': case ' ': case ';': case ':': escapedpath += '\\'; } escapedpath += *p; } return escapedpath; } void splitPath(const char *path, std::vector &result) { char *sp; char *xpath = strdup(path); char *p = strtok_r(xpath, ":", &sp); if (!xpath) abort(); while (p) { result.push_back(p); p = strtok_r(NULL, ":", &sp); } free(xpath); } std::string joinPath(const std::vector &path) { std::string tmp; std::string escaped; for (size_t i = 0; i < path.size(); ++i) { escaped.clear(); tmp += escapePath(path[i], escaped); if (i != path.size() - 1) tmp += ":"; } return tmp; } bool hasPath(const std::vector &path, const char *find) { for (const std::string &p : path) if (p == find) return true; return false; } // // Files and Directories // std::string *getFileContent(const std::string &file, std::string &content) { std::ifstream f(file.c_str()); if (!f.is_open()) return nullptr; f.seekg(0, std::ios::end); auto len = f.tellg(); f.seekg(0, std::ios::beg); if (len != static_cast(-1)) content.reserve(static_cast(f.tellg())); content.assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); return &content; } bool writeFileContent(const std::string &file, const std::string &content) { std::ofstream f(file.c_str()); if (!f.is_open()) return false; f << content; return f.good(); } bool fileExists(const std::string &file) { struct stat st; return !stat(file.c_str(), &st); } bool dirExists(const std::string &dir) { struct stat st; return !stat(dir.c_str(), &st) && S_ISDIR(st.st_mode); } typedef bool (*listfilescallback)(const char *file); bool isDirectory(const char *file, const char *prefix) { struct stat st; if (prefix) { std::string tmp = prefix; tmp += "/"; tmp += file; return !stat(tmp.c_str(), &st) && S_ISDIR(st.st_mode); } else { return !stat(file, &st) && S_ISDIR(st.st_mode); } } bool listFiles(const char *dir, std::vector *files, listfilescallback cmp) { #ifndef _WIN32 DIR *d = opendir(dir); dirent *de; if (!d) return false; while ((de = readdir(d))) { if ((!cmp || cmp(de->d_name)) && files) { files->push_back(de->d_name); } } closedir(d); return true; #else WIN32_FIND_DATA fdata; HANDLE handle; handle = FindFirstFile(dir, &fdata); if (handle == INVALID_HANDLE_VALUE) return false; do { if ((!cmp || cmp(fdata.cFileName)) && files) { files->push_back(fdata.cFileName); } } while (FindNextFile(handle, &fdata)); FindClose(handle); return true; #endif } typedef bool (*realpathcmp)(const char *file, const struct stat &st); bool isExecutable(const char *f, const struct stat &) { return !access(f, F_OK | X_OK); } bool ignoreCCACHE(const char *f, const struct stat &) { const char *name = getFileName(f); return name && strstr(name, "ccache") != name; } bool realPath(const char *file, std::string &result, realpathcmp cmp1, realpathcmp cmp2) { char *PATH = getenv("PATH"); const char *p = PATH ? PATH : ""; struct stat st; result.clear(); do { if (*p == ':') ++p; while (*p && *p != ':') result += *p++; result += "/"; result += file; if (!stat(result.c_str(), &st)) { #ifndef _WIN32 char buf[PATH_MAX + 1]; if (realpath(result.c_str(), buf)) { result.assign(buf); } else { ssize_t len; char path[PATH_MAX]; size_t pathlen; size_t n = 0; pathlen = result.find_last_of(PATHDIV); if (pathlen == std::string::npos) pathlen = result.length(); else ++pathlen; // PATHDIV memcpy(path, result.c_str(), pathlen); // not null terminated while ((len = readlink(result.c_str(), buf, PATH_MAX)) != -1) { if (buf[0] != PATHDIV) { result.assign(path, pathlen); result.append(buf, len); } else { result.assign(buf, len); pathlen = strrchr(buf, PATHDIV) - buf + 1; // + 1: PATHDIV memcpy(path, buf, pathlen); } if (++n >= 1000) { err << result << ": too many levels of symbolic links" << err.endl(); result.clear(); break; } } } #endif if ((!cmp1 || cmp1(result.c_str(), st)) && (!cmp2 || cmp2(result.c_str(), st))) break; } result.clear(); } while (*p); return !result.empty(); } bool getPathOfCommand(const char *command, std::string &result, realpathcmp cmp) { if (realPath(command, result, isExecutable, cmp)) stripFileName(result); return !result.empty(); } void stripFileName(std::string &path) { size_t lastpathdiv = path.find_last_of(PATHDIV); if (lastpathdiv != 0 && lastpathdiv != std::string::npos) path.resize(lastpathdiv); } const char *getFileName(const char *file) { const char *p = strrchr(file, PATHDIV); if (!p) p = file; else ++p; return p; } const char *getFileExtension(const char *file) { const char *p = strrchr(file, '.'); if (!p) p = ""; return p; } // // Time // time_type getNanoSeconds() { #ifdef __APPLE__ union { AbsoluteTime at; time_type ull; } tmp; tmp.ull = mach_absolute_time(); Nanoseconds ns = AbsoluteToNanoseconds(tmp.at); tmp.ull = UnsignedWideToUInt64(ns); return tmp.ull; #elif defined(__linux__) struct timespec tp; if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) return static_cast((tp.tv_sec * 1000000000LL) + tp.tv_nsec); #endif struct timeval tv; if (gettimeofday(&tv, nullptr) == 0) return static_cast((tv.tv_sec * 1000000000LL) + (tv.tv_usec * 1000)); abort(); } // // OSVersion // OSVersion parseOSVersion(const char *OSVer) { const char *p = OSVer; OSVersion OSNum; OSNum.major = atoi(p); while (*p && *p++ != '.') ; if (!*p) return OSNum; OSNum.minor = atoi(p); while (*p && *p++ != '.') ; if (!*p) return OSNum; OSNum.patch = atoi(p); return OSNum; } // // OS Compat // #ifdef _WIN32 int setenv(const char *name, const char *value, int overwrite) { std::string buf; (void)overwrite; // TODO buf = name; buf += '='; buf += value; return putenv(buf.c_str()); } int unsetenv(const char *name) { return setenv(name, "", 1); } #endif } // namespace tools