Get the path of ruby binary
diff --git a/ext/etc/etc.c b/ext/etc/etc.c | |
index 2bd2e30..9da0ed7 100644 | |
--- a/ext/etc/etc.c | |
+++ b/ext/etc/etc.c | |
@@ -597,6 +597,155 @@ etc_systmpdir(void) | |
return tmpdir; | |
} | |
+#ifdef _WIN32 | |
+# define RUBYPATH_GetModuleFileName | |
+#elif defined(__APPLE__) | |
+# define RUBYPATH_NSGetExecutablePath | |
+# include <mach-o/dyld.h> | |
+#elif defined(__sun__) | |
+# define RUBYPATH_getexecname | |
+#elif defined(_AIX) || defined(__OpenBSD__) | |
+# define RUBYPATH_dladdr | |
+# include <dlfcn.h> | |
+#elif defined(__FreeBSD__) | |
+# define RUBYPATH_sysctl | |
+# include <sys/sysctl.h> | |
+# include <errno.h> | |
+#elif defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__) | |
+# define RUBYPATH_procfs | |
+#endif | |
+ | |
+/* | |
+ * call-seq: | |
+ * Etc.rubypath -> string | |
+ * | |
+ * Returns the real absolute path of current executing ruby. | |
+ * "real" means it doesn't include symlinks. | |
+ * If the environment doesn't support this, raises NotImplementedError. | |
+ * | |
+ * Example in shell: | |
+ * % pwd | |
+ * /hoge | |
+ * % ls -l | |
+ * lrwxr-xr-x 1 rubyist users 32 Jan 1 00:00 foo -> /usr/local/bin/ruby | |
+ * % ./foo -retc -e'puts Etc.rubypath' | |
+ * /usr/local/bin/ruby | |
+ * % cd / | |
+ * % PATH=/hoge foo -retc -e'puts Etc.rubypath' | |
+ * /usr/local/bin/ruby | |
+ */ | |
+static VALUE | |
+etc_rubypath(void) | |
+{ | |
+#ifdef RUBYPATH_GetModuleFileName | |
+ char buf[4096]; | |
+ size_t len; | |
+ len = (size_t)GetModuleFileName(NULL, buf, sizeof(buf)); | |
+ if (len == 0) rb_sys_fail("Can't get the path of ruby"); | |
+ return rb_filesystem_str_new(buf, len); | |
+#elif defined(RUBYPATH_NSGetExecutablePath) | |
+ /* | |
+ * defined(__APPLE__): returns absolute but symlink; need realpath | |
+ */ | |
+ VALUE v; | |
+ uint32_t len = 0; | |
+ char *buf, *resolved | |
+ int err; | |
+ _NSGetExecutablePath(NULL, &len); | |
+ buf = malloc(len); | |
+ if (buf == NULL) rb_sys_fail("Can't allocate memory"); | |
+ err = _NSGetExecutablePath(buf, &len); | |
+ if (err != 0) rb_sys_fail("Can't get the path of ruby"); | |
+ resolved = realpath(buf, NULL); | |
+ if (resolved == NULL) rb_sys_fail("Can't get the path of ruby"); | |
+ v = rb_filesystem_str_new_cstr(resolved); | |
+ free(buf); | |
+ free(resolved); | |
+ return v; | |
+#elif defined(RUBYPATH_getexecname) | |
+ const char *name = getexecname(); | |
+ if (name == NULL) rb_sys_fail("Can't get the path of ruby"); | |
+ return rb_filesystem_str_new_cstr(name); | |
+#elif defined(RUBYPATH_dladdr) | |
+ /* | |
+ * defined(__FreeBSD__): returns absolute but symlink; need realpath | |
+ * defined(__NetBSD__): returns relative; can't use | |
+ * defined(__OpenBSD__): returns relative; can't use | |
+ * defined(__DragonFly__): returns relative; can't use | |
+ * defined(__sun__): | |
+ * defined(_AIX): | |
+ * defined(__APPLE__): returns absolute but symlink; need realpath | |
+ * | |
+ * On relative platform, dln_find_exe can be used. | |
+ */ | |
+ VALUE v; | |
+ char *resolved; | |
+ Dl_info info; | |
+ extern char **environ; /* environ should be in "ruby" not libruby */ | |
+ if (dladdr(&environ, &info) == 0) | |
+ rb_sys_fail("Can't get the path of ruby"); | |
+ resolved = realpath(info.dli_fname, NULL); /* realpath(, NULL) is platform dependent */ | |
+ if (resolved == NULL) rb_sys_fail("Can't get the path of ruby"); | |
+ v = rb_filesystem_str_new_cstr(resolved); | |
+ free(resolved); | |
+ return v; | |
+#elif defined(RUBYPATH_sysctl) | |
+ /* | |
+ * defined(__FreeBSD__): returns absolute | |
+ */ | |
+ VALUE v; | |
+ int mib[4], err; | |
+ char *buf; | |
+ size_t len = 0; | |
+ mib[0] = CTL_KERN; | |
+ mib[1] = KERN_PROC; | |
+ mib[2] = KERN_PROC_PATHNAME; | |
+ mib[3] = -1; | |
+ err = sysctl(mib, 4, NULL, &len, NULL, 0); | |
+ if (err) rb_sys_fail("Can't get the path of ruby"); | |
+ buf = malloc(len); | |
+ if (buf == NULL) rb_sys_fail("Can't allocate memory"); | |
+ err = sysctl(mib, 4, buf, &len, NULL, 0); | |
+ if (err) { | |
+ free(buf); | |
+ rb_sys_fail("Can't get the path of ruby"); | |
+ } | |
+ len--; | |
+ v = rb_filesystem_str_new(buf, len); | |
+ free(buf); | |
+ return v; | |
+#elif defined(RUBYPATH_procfs) | |
+ /* | |
+ * defined(__linux__): returns absolute | |
+ * defined(__NetBSD__): returns absolute | |
+ * defined(__DragonFly__): returns absolute | |
+ */ | |
+ VALUE v; | |
+ size_t bufsiz = PATH_MAX; | |
+ char buf[PATH_MAX]; | |
+ ssize_t len = 0; | |
+# if defined(__linux__) /* solaris 10+ */ | |
+ len = readlink("/proc/self/exe", buf, bufsiz); | |
+# elif defined(__DragonFly__) | |
+ len = readlink("/proc/curproc/file", buf, bufsiz); | |
+# elif defined(__NetBSD__) | |
+ len = readlink("/proc/curproc/exe", buf, bufsiz); | |
+# else | |
+ rb_notimplement(); | |
+# endif | |
+ if (len < 0) { | |
+ rb_sys_fail("Can't get the path of ruby"); | |
+ } | |
+ /* assume PATH_MAX is enough length */ | |
+ v = rb_filesystem_str_new(buf, len); | |
+ return v; | |
+#else | |
+ rb_notimplement(); | |
+ return Qnil; /* dummy */ | |
+#endif | |
+} | |
+ | |
/* | |
* The etc module provides access to information from the running OS. | |
* | |
@@ -625,6 +774,7 @@ Init_etc(void) | |
rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0); | |
rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0); | |
rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0); | |
+ rb_define_module_function(mEtc, "rubypath", etc_rubypath, 0); | |
sPasswd = rb_struct_define("Passwd", | |
"name", "passwd", "uid", "gid", |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
TODO: