| 1136 | } |
| 1137 | |
| 1138 | String OS_Unix::get_executable_path() const { |
| 1139 | #ifdef __linux__ |
| 1140 | //fix for running from a symlink |
| 1141 | char buf[PATH_MAX]; |
| 1142 | memset(buf, 0, PATH_MAX); |
| 1143 | ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)); |
| 1144 | String b; |
| 1145 | if (len > 0) { |
| 1146 | b.append_utf8(buf, len); |
| 1147 | } |
| 1148 | if (b.is_empty()) { |
| 1149 | WARN_PRINT("Couldn't get executable path from /proc/self/exe, using argv[0]"); |
| 1150 | return OS::get_executable_path(); |
| 1151 | } |
| 1152 | return b; |
| 1153 | #elif defined(__OpenBSD__) |
| 1154 | std::string path; |
| 1155 | auto cpp_getexe = [](std::string exe) { |
| 1156 | int cntp = 0; |
| 1157 | std::string res; |
| 1158 | kvm_t *kd = nullptr; |
| 1159 | kinfo_file *kif = nullptr; |
| 1160 | bool error1 = false, error2 = false; |
| 1161 | kd = kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr); |
| 1162 | if (kd) { |
| 1163 | if ((kif = kvm_getfiles(kd, KERN_FILE_BYPID, getpid(), sizeof(struct kinfo_file), &cntp))) { |
| 1164 | for (int i = 0; i < cntp && kif[i].fd_fd < 0; i++) { |
| 1165 | if (kif[i].fd_fd == KERN_FILE_TEXT) { |
| 1166 | fallback: |
| 1167 | struct stat st; |
| 1168 | char buffer[PATH_MAX]; |
| 1169 | if (!stat(exe.c_str(), &st) && (st.st_mode & S_IXUSR) && |
| 1170 | S_ISREG(st.st_mode) && realpath(exe.c_str(), buffer) && |
| 1171 | st.st_dev == (dev_t)kif[i].va_fsid && st.st_ino == (ino_t)kif[i].va_fileid) { |
| 1172 | res = buffer; |
| 1173 | } |
| 1174 | if (res.empty() && !error1) { |
| 1175 | error1 = true; |
| 1176 | size_t last_slash_pos = exe.find_last_of("/"); |
| 1177 | if (last_slash_pos != std::string::npos) { |
| 1178 | exe = exe.substr(0, last_slash_pos + 1) + kif[i].p_comm; |
| 1179 | goto fallback; |
| 1180 | } |
| 1181 | } |
| 1182 | if (res.empty() && !error2) { |
| 1183 | error2 = true; |
| 1184 | size_t last_slash_pos = exe.find_last_of("/"); |
| 1185 | if (last_slash_pos != std::string::npos) { |
| 1186 | const char *progname = getprogname(); |
| 1187 | if (progname) { |
| 1188 | exe = exe.substr(0, last_slash_pos + 1) + progname; |
| 1189 | goto fallback; |
| 1190 | } |
| 1191 | } |
| 1192 | } |
| 1193 | break; |
| 1194 | } |
| 1195 | } |