non-root binary distribution

D

David Garamond

Is there a binary .tar.gz or a relocatable RPM for ruby 1.8.x which can
be installed onto a custom per-user directory without requiring root
privilege? I find it easy to do this with the mswin32 version.
 
N

nobu.nokada

Hi,

At Wed, 3 Mar 2004 01:05:21 +0900,
David Garamond wrote in [ruby-talk:94067]:
Is there a binary .tar.gz or a relocatable RPM for ruby 1.8.x which can
be installed onto a custom per-user directory without requiring root
privilege? I find it easy to do this with the mswin32 version.

Ruby embeds absolute load paths, for the sake of UNIX tradition
and security issue.

However, it might not be major problem if $SAFE == 0, so you
could make relocatable binary with the following path and
--enable-load-relative configure option, if you use /proc fs on
linux.


* configure.in (load-relative): separate load-relative feature from
platform.

* ruby.c (ruby_init_loadpath): appendant to load-relative feature.
[ruby-talk:94067]


Index: configure.in
===================================================================
RCS file: /cvs/ruby/src/ruby/configure.in,v
retrieving revision 1.226
diff -u -2 -p -d -r1.226 configure.in
--- configure.in 16 Feb 2004 06:45:31 -0000 1.226
+++ configure.in 3 Mar 2004 01:52:44 -0000
@@ -1387,13 +1387,27 @@ case "$target_os" in
;;
esac
+
+AC_ARG_ENABLE(load-relative,
+ [ --enable-load-relative enable initial load path relative to ruby],
+ [loadrelative=$enableval], [loadrelative=no])
+
case "$target_os" in
cygwin*|mingw*|*djgpp*|os2-emx*)
- RUBY_LIB_PREFIX="/lib/ruby"
+ loadrelative=yes
+ ;;
+ linux*)
;;
*)
- RUBY_LIB_PREFIX="${prefix}/lib/ruby"
+ loadrelative=no
;;
esac
-RUBY_LIB_PATH="${RUBY_LIB_PREFIX}/${MAJOR}.${MINOR}"
+if test "x$loadrelative" = xyes; then
+ AC_DEFINE(LOAD_RELATIVE, 1)
+ AC_DEFINE_UNQUOTED(RUBY_PREFIX, "${prefix}")
+ RUBY_PREFIX=""
+else
+ RUBY_PREFIX="${prefix}"
+fi
+RUBY_LIB_PATH="${RUBY_PREFIX}/lib/ruby/${MAJOR}.${MINOR}"

AC_ARG_WITH(sitedir,
@@ -1402,11 +1416,6 @@ AC_ARG_WITH(sitedir,
[sitedir='${prefix}/lib/ruby/site_ruby'])
SITE_DIR="`eval \"echo ${sitedir}\"`"
-case "$target_os" in
- cygwin*|mingw*|*djgpp*|os2-emx*)
- RUBY_SITE_LIB_PATH="`expr "$SITE_DIR" : "$prefix\(/.*\)"`" ||
- RUBY_SITE_LIB_PATH="$SITE_DIR";;
- *)
- RUBY_SITE_LIB_PATH="$SITE_DIR";;
-esac
+RUBY_SITE_LIB_PATH="${RUBY_PREFIX}`expr "$SITE_DIR" : "$prefix\(/.*\)"`" ||
+RUBY_SITE_LIB_PATH="$SITE_DIR"
RUBY_SITE_LIB_PATH2="${RUBY_SITE_LIB_PATH}/${MAJOR}.${MINOR}"

Index: ruby.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ruby.c,v
retrieving revision 1.86
diff -u -2 -p -d -r1.86 ruby.c
--- ruby.c 21 Jan 2004 16:47:14 -0000 1.86
+++ ruby.c 3 Mar 2004 01:58:56 -0000
@@ -233,4 +233,37 @@ translate_char(p, from, to)
#endif

+#if defined LOAD_RELATIVE && defined RUBY_PREFIX
+#ifdef __linux__
+static char *
+getlibpath(lib, size, pos)
+ char *lib;
+ int size;
+ long pos;
+{
+ FILE *maps = fopen("/proc/self/maps", "r");
+ long start, end;
+ char *p;
+
+ if (!maps) return 0;
+ *lib = 0;
+ while (fscanf(maps, "%x-%x", &start, &end) == 2) {
+ if (start <= pos && pos < end) {
+ fscanf(maps, " %*s %*s %*s %*s ");
+ fgets(lib, size, maps);
+ fclose(maps);
+ p = strchr(lib, '\n');
+ if (p) *p = 0;
+ return lib;
+ }
+ else {
+ fscanf(maps, "%*[^\n]\n");
+ }
+ }
+ fclose(maps);
+ return 0;
+}
+#endif
+#endif
+
void
ruby_init_loadpath()
@@ -258,4 +291,11 @@ ruby_init_loadpath()
#elif defined(__EMX__)
_execname(libpath, FILENAME_MAX);
+#elif defined(RUBY_PREFIX)
+ if (rb_safe_level() > 0 ||
+ !getlibpath(libpath, sizeof libpath, (long)ruby_init_loadpath)) {
+ strncpy(libpath, RUBY_PREFIX, sizeof libpath);
+ p = libpath + strlen(libpath);
+ goto init;
+ }
#endif

@@ -267,5 +307,6 @@ ruby_init_loadpath()
if (p) {
*p = 0;
- if (p-libpath > 3 && !strcasecmp(p-4, "/bin")) {
+ if (p-libpath > 3 &&
+ !(strcasecmp(p-4, "/bin") && strcasecmp(p-4, "/lib"))) {
p -= 4;
*p = 0;
@@ -277,4 +318,5 @@ ruby_init_loadpath()
}

+ init:
rest = FILENAME_MAX - (p - libpath);
 
D

David Garamond

Ruby embeds absolute load paths, for the sake of UNIX tradition
and security issue.

However, it might not be major problem if $SAFE == 0, so you
could make relocatable binary with the following path and
--enable-load-relative configure option, if you use /proc fs on
linux.

Thanks, it works beautifully. The only thing left is that a user needs
to do:

% LD_LIBRARY_PATH=/path/to/his/ruby/lib /path/to/his/ruby/bin/ruby

(or set LD_LIBRARY_PATH in his ~/.bash_profile) otherwise ruby can't
find libruby.so. Is there a way to avoid/get around this?
 
N

nobu.nokada

Hi,

At Thu, 4 Mar 2004 01:54:48 +0900,
David Garamond wrote in [ruby-talk:94160]:
Thanks, it works beautifully. The only thing left is that a user needs
to do:

% LD_LIBRARY_PATH=/path/to/his/ruby/lib /path/to/his/ruby/bin/ruby

(or set LD_LIBRARY_PATH in his ~/.bash_profile) otherwise ruby can't
find libruby.so. Is there a way to avoid/get around this?

a) use static linked ruby
configure --disable-shared

b) prepare a wrapper script like followings, with renaming ruby
to ruby-bin.

#!/bin/sh
LD_LIBRARY_PATH="${0%/*}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" exec "$0-bin" "$@"

Although it doesn't work in shebang lines, of course, you may
not use user specific paths.
 
D

David Garamond

a) use static linked ruby
configure --disable-shared

b) prepare a wrapper script like followings, with renaming ruby
to ruby-bin.

#!/bin/sh
LD_LIBRARY_PATH="${0%/*}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" exec "$0-bin" "$@"

Although it doesn't work in shebang lines, of course, you may
not use user specific paths.

Based on your suggestion, I've created a C wrapper like below. The real
ruby is renamed to "ruby.real". Advice welcome, since this is probably
only the 7th or 8th C program I've written, ever. :)



#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
static char binpath[512+5], libpath[512+6];
char *p, *env;

if (readlink("/proc/self/exe", binpath, 511) == -1) {
fprintf(stderr, "readlink() failed: %s (maybe /proc is not "
"mounted or restricted?)\n", strerror(errno));
exit(1);
}

strcpy(libpath, binpath);
p = libpath + strlen(libpath);
while (p >= libpath) {
if (*p == '/') {
strcpy(p, "/../lib");
break;
}
p--;
}

p = (char *)getenv("LD_LIBRARY_PATH");
if ((env = (char *)malloc(512+1+(p==NULL ? 0:strlen(p)))) == NULL) {
fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
exit(1);
}
strcat(env, "LD_LIBRARY_PATH=");
if (p != NULL) {
strcat(env, p);
strcat(env, ":");
}
strcat(env, libpath);
if (putenv(env) == -1) {
fprintf(stderr, "putenv() failed: %s\n", strerror(errno));
exit(1);
}

strcat(binpath, ".real");
execv(binpath, argv);
fprintf(stderr, "Can't execute wrapee: %s\n", strerror(errno));
exit(1);
}
 
N

nobu.nokada

Hi,

At Fri, 5 Mar 2004 00:51:39 +0900,
David Garamond wrote in [ruby-talk:94230]:
Based on your suggestion, I've created a C wrapper like below. The real
ruby is renamed to "ruby.real". Advice welcome, since this is probably
only the 7th or 8th C program I've written, ever. :)

I recommend static-linked binary after all. You'd have no merit
of shared library at all if you put the copy in each users'
space.
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
static char binpath[512+5], libpath[512+6];

You'd better to get rid of magic numbers.
p = (char *)getenv("LD_LIBRARY_PATH");
if ((env = (char *)malloc(512+1+(p==NULL ? 0:strlen(p)))) == NULL) {
fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
exit(1);
}
strcat(env, "LD_LIBRARY_PATH=");

Use strcpy instead of strcat here, content of malloc'ed area is
not guaranteed.
 
D

David Garamond

I recommend static-linked binary after all. You'd have no merit
of shared library at all if you put the copy in each users'
space.

But will static Ruby be problematic when building extensions? For
example, I tried with plruby and it didn't produce a proper plruby.so.
Maybe most Ruby extensions are developed with a shared Ruby in mind.
#include <stdio.h>
#include <errno.h>

int main(int argc, char *argv[]) {
static char binpath[512+5], libpath[512+6];

You'd better to get rid of magic numbers.
p = (char *)getenv("LD_LIBRARY_PATH");
if ((env = (char *)malloc(512+1+(p==NULL ? 0:strlen(p)))) == NULL) {
fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
exit(1);
}
strcat(env, "LD_LIBRARY_PATH=");

Use strcpy instead of strcat here, content of malloc'ed area is
not guaranteed.

Thanks for the suggestions.
 
N

nobu.nokada

Hi,

At Fri, 5 Mar 2004 19:51:08 +0900,
David Garamond wrote in [ruby-talk:94318]:
But will static Ruby be problematic when building extensions? For
example, I tried with plruby and it didn't produce a proper plruby.so.
Maybe most Ruby extensions are developed with a shared Ruby in mind.

Don't worry, even with --disable-shared, standard extension
libraries are built properly.

I don't know how "it didn't produce a proper" so, but think the
reason would be another problem.
 
D

David Garamond

At Fri, 5 Mar 2004 19:51:08 +0900,
David Garamond wrote in [ruby-talk:94318]:
But will static Ruby be problematic when building extensions? For
example, I tried with plruby and it didn't produce a proper plruby.so.
Maybe most Ruby extensions are developed with a shared Ruby in mind.

Don't worry, even with --disable-shared, standard extension
libraries are built properly.
I don't know how "it didn't produce a proper" so, but think the
reason would be another problem.

Yes, standard extension are all built successfully. I also just tried
building ruby-postgres and mysql-ruby with no problem. I guess plruby is
a different case as it tries to link with ruby itself.

Thanks,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top