1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <sys/stat.h>
  27 #include <unistd.h>
  28 #include <mach-o/dyld.h>
  29 #include "FileUtils.h"
  30 #include "ErrorHandling.h"
  31 
  32 namespace SysInfo {
  33 
  34 tstring getRealPath(std::vector<char> in) {
  35     std::vector<char> out(PATH_MAX);
  36 
  37     struct stat sb;
  38     if (lstat(in.data(), &sb) == -1) {
  39         JP_THROW(tstrings::any() << "lstat(" << in.data()
  40                 << ") failed. Error: " << lastCRTError());
  41     }
  42 
  43     // readlink() will fail if called on real path, so if we have real path, then just
  44     // use it
  45     if (!S_ISLNK(sb.st_mode)) {
  46         return tstring(in.data(), in.size() - 1 /* don't count trailing '0' */);
  47     }
  48 
  49     // Get real path, since _NSGetExecutablePath can return symbolic link
  50     ssize_t len = readlink(in.data(), out.data(), PATH_MAX);
  51     if (len < 0) {
  52         JP_THROW(tstrings::any() << "readlink(" << in.data()
  53                 << ") failed. Error: " << lastCRTError());
  54     }
  55 
  56     return tstring(out.data(), len);
  57 }
  58 
  59 tstring getProcessModulePath() {
  60     std::vector<char> buffer;
  61     uint32_t bufferSize = 0;
  62     do {
  63         int len = _NSGetExecutablePath(buffer.data(), &bufferSize);
  64         if (len == 0) {
  65             break;
  66         }
  67 
  68         if (len > 0) {
  69             JP_THROW(tstrings::any() << "_NSGetExecutablePath() failed");
  70         }
  71 
  72         buffer.resize(bufferSize);
  73     } while (true);
  74 
  75     tstring reply = getRealPath(buffer);
  76 
  77     return FileUtils::toAbsolutePath(reply);
  78 }
  79 
  80 } // end of namespace SysInfo