Skip to content

Commit b9b484f

Browse files
Add More Reliable OpenBSD Executable Path Solution
1 parent 5f54c0d commit b9b484f

1 file changed

Lines changed: 130 additions & 6 deletions

File tree

drivers/unix/os_unix.cpp

Lines changed: 130 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,18 @@
6363
#include <sys/sysctl.h>
6464
#endif
6565

66-
#if defined(__FreeBSD__)
66+
#if defined(__FreeBSD__) || defined(__OpenBSD__)
6767
#include <kvm.h>
6868
#endif
6969

7070
#if defined(__OpenBSD__)
7171
#include <sys/swap.h>
72+
#include <sys/types.h>
7273
#include <uvm/uvmexp.h>
74+
#include <climits>
75+
#include <sstream>
76+
#include <string>
77+
#include <vector>
7378
#endif
7479

7580
#if defined(__NetBSD__)
@@ -1146,11 +1151,130 @@ String OS_Unix::get_executable_path() const {
11461151
}
11471152
return b;
11481153
#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());
11541278
#elif defined(__NetBSD__)
11551279
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
11561280
char buf[MAXPATHLEN];

0 commit comments

Comments
 (0)