Last active
September 26, 2015 16:57
-
-
Save nurse/1129437 to your computer and use it in GitHub Desktop.
Get the path of ruby binary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
TODO: