|
63 | 63 | #include <sys/sysctl.h> |
64 | 64 | #endif |
65 | 65 |
|
66 | | -#if defined(__FreeBSD__) |
| 66 | +#if defined(__FreeBSD__) || defined(__OpenBSD__) |
67 | 67 | #include <kvm.h> |
68 | 68 | #endif |
69 | 69 |
|
70 | 70 | #if defined(__OpenBSD__) |
71 | 71 | #include <sys/swap.h> |
| 72 | +#include <sys/types.h> |
72 | 73 | #include <uvm/uvmexp.h> |
| 74 | +#include <climits> |
| 75 | +#include <sstream> |
| 76 | +#include <string> |
| 77 | +#include <vector> |
73 | 78 | #endif |
74 | 79 |
|
75 | 80 | #if defined(__NetBSD__) |
@@ -1146,11 +1151,130 @@ String OS_Unix::get_executable_path() const { |
1146 | 1151 | } |
1147 | 1152 | return b; |
1148 | 1153 | #elif defined(__OpenBSD__) |
1149 | | - char resolved_path[MAXPATHLEN]; |
1150 | | - |
1151 | | - realpath(OS::get_executable_path().utf8().get_data(), resolved_path); |
1152 | | - |
1153 | | - return String(resolved_path); |
| 1154 | + std::string path; |
| 1155 | + auto is_exe = [](std::string exe) { |
| 1156 | + int cntp = 0; |
| 1157 | + std::string res; |
| 1158 | + kvm_t *kd = nullptr; |
| 1159 | + kinfo_file *kif = nullptr; |
| 1160 | + bool error = false; |
| 1161 | + kd = kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr); |
| 1162 | + if (!kd) return res; |
| 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 | + struct stat st; |
| 1167 | + fallback: |
| 1168 | + char buffer[PATH_MAX]; |
| 1169 | + if (!stat(exe.c_str(), &st) && (st.st_mode & S_IXUSR) && |
| 1170 | + (st.st_mode & S_IFREG) && 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() && !error) { |
| 1175 | + error = true; |
| 1176 | + std::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 | + break; |
| 1183 | + } |
| 1184 | + } |
| 1185 | + } |
| 1186 | + kvm_close(kd); |
| 1187 | + return res; |
| 1188 | + }; |
| 1189 | + auto cppstr_getenv = [](std::string name) { |
| 1190 | + const char *cresult = getenv(name.c_str()); |
| 1191 | + std::string result = cresult ? cresult : ""; |
| 1192 | + return result; |
| 1193 | + }; |
| 1194 | + int cntp = 0; |
| 1195 | + kvm_t *kd = nullptr; |
| 1196 | + kinfo_proc *proc_info = nullptr; |
| 1197 | + std::vector<std::string> buffer; |
| 1198 | + bool error = false, retried = false; |
| 1199 | + kd = kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr); |
| 1200 | + if (!kd) { |
| 1201 | + path.clear(); |
| 1202 | + return path; |
| 1203 | + } |
| 1204 | + if ((proc_info = kvm_getprocs(kd, KERN_PROC_PID, getpid(), sizeof(struct kinfo_proc), &cntp))) { |
| 1205 | + char **cmd = kvm_getargv(kd, proc_info, 0); |
| 1206 | + if (cmd) { |
| 1207 | + for (int i = 0; cmd[i]; i++) { |
| 1208 | + buffer.push_back(cmd[i]); |
| 1209 | + } |
| 1210 | + } |
| 1211 | + } |
| 1212 | + kvm_close(kd); |
| 1213 | + if (!buffer.empty()) { |
| 1214 | + std::string argv0; |
| 1215 | + if (!buffer[0].empty()) { |
| 1216 | + fallback: |
| 1217 | + std::size_t slash_pos = buffer[0].find('/'); |
| 1218 | + std::size_t colon_pos = buffer[0].find(':'); |
| 1219 | + if (slash_pos == 0) { |
| 1220 | + argv0 = buffer[0]; |
| 1221 | + path = is_exe(argv0); |
| 1222 | + } else if (slash_pos == std::string::npos || slash_pos > colon_pos) { |
| 1223 | + std::string penv = cppstr_getenv("PATH"); |
| 1224 | + if (!penv.empty()) { |
| 1225 | + retry: |
| 1226 | + std::string tmp; |
| 1227 | + std::stringstream sstr(penv); |
| 1228 | + while (std::getline(sstr, tmp, ':')) { |
| 1229 | + argv0 = tmp + "/" + buffer[0]; |
| 1230 | + path = is_exe(argv0); |
| 1231 | + if (!path.empty()) break; |
| 1232 | + if (slash_pos > colon_pos) { |
| 1233 | + argv0 = tmp + "/" + buffer[0].substr(0, colon_pos); |
| 1234 | + path = is_exe(argv0); |
| 1235 | + if (!path.empty()) break; |
| 1236 | + } |
| 1237 | + } |
| 1238 | + } |
| 1239 | + if (path.empty() && !retried) { |
| 1240 | + retried = true; |
| 1241 | + penv = "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin"; |
| 1242 | + std::string home = cppstr_getenv("HOME"); |
| 1243 | + if (!home.empty()) { |
| 1244 | + penv = home + "/bin:" + penv; |
| 1245 | + } |
| 1246 | + goto retry; |
| 1247 | + } |
| 1248 | + } |
| 1249 | + if (path.empty() && slash_pos > 0) { |
| 1250 | + std::string pwd = cppstr_getenv("PWD"); |
| 1251 | + if (!pwd.empty()) { |
| 1252 | + argv0 = pwd + "/" + buffer[0]; |
| 1253 | + path = is_exe(argv0); |
| 1254 | + } |
| 1255 | + if (path.empty()) { |
| 1256 | + char cwd[PATH_MAX]; |
| 1257 | + if (getcwd(cwd, PATH_MAX)) { |
| 1258 | + argv0 = std::string(cwd) + "/" + buffer[0]; |
| 1259 | + path = is_exe(argv0); |
| 1260 | + } |
| 1261 | + } |
| 1262 | + } |
| 1263 | + } |
| 1264 | + if (path.empty() && !error) { |
| 1265 | + error = true; |
| 1266 | + buffer.clear(); |
| 1267 | + std::string underscore = cppstr_getenv("_"); |
| 1268 | + if (!underscore.empty()) { |
| 1269 | + buffer.push_back(underscore); |
| 1270 | + goto fallback; |
| 1271 | + } |
| 1272 | + } |
| 1273 | + } |
| 1274 | + if (!path.empty()) { |
| 1275 | + errno = 0; |
| 1276 | + } |
| 1277 | + return String(path.c_str()); |
1154 | 1278 | #elif defined(__NetBSD__) |
1155 | 1279 | int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; |
1156 | 1280 | char buf[MAXPATHLEN]; |
|
0 commit comments