Is it possible to force a Ruby program to run as a proc name different than "ruby"?

Hi, I have a Python software called "py_program". It runs as daemon in Linux
so doing a "ps" I get:

  root 6541 /usr/bin/python /home/ibc/py_program

However in /proc/6541/status I read:

  Name: py_program

This is good because this means that in Debian it can be stopped with the
command:

  start-stop-daemon --stop --name py_program

Anyhow the proces name is "python" still rather than "py_program":

  ~# netstat -putan | grep 6541
  6541/python

and I cannot kill the process with "killall py_program".

Well, I'm coding a server "rb_program" in Ruby (a HTTP server built with Rack)
and the behavior is different:

  root 5412 ruby1.9 /home/ibc/rb_program

In /proc/5412/status:

  Name: ruby1.9

So I cannot use "start-stop-daemon --stop --name rb_program" because it would
find no process names "rb_program"
(and of course I cannot use "--name ruby1.9" as I would stop any ruby program
running in the host).

So, is there some way to force the process to appear as "rb_program" in
/proc/PID/status?

Thanks a lot.

···

--
Iñaki Baz Castillo <ibc@aliax.net>

I forgot to say that a dirty workaround is creating a link to ruby binary
called "rb_program".

Of course is really dirty :slight_smile:

···

El Viernes, 11 de Diciembre de 2009, Iñaki Baz Castillo escribió:

So, is there some way to force the process to appear as "rb_program" in
/proc/PID/status?

--
Iñaki Baz Castillo <ibc@aliax.net>

This is good because this means that in Debian it can be stopped with the
command:

  start-stop-daemon --stop --name py_program

[snip]

So I cannot use "start-stop-daemon --stop --name rb_program" because it
would find no process names "rb_program"

This is probably not a good idea in the first place -- it means you can't have
separate copies of the program running, and start/stop them independently, to
say nothing of the possibility that some other program might share the same
name.

Since you're using start-stop-daemon anyway, why don't you make a pidfile?

start-stop-daemon --start --startas /home/ibc/rb_program --make-pidfile --
pidfile /var/run/rb_program.pid --background

If your program is backgrounding itself already, configure it to create its
own pidfile -- shouldn't be too hard. Then you can do this instead:

start-stop-daemon --stop --pidfile /var/run/rb_program.pid

So, is there some way to force the process to appear as "rb_program" in
/proc/PID/status?

I'd like to know that, too, because it'd be useful for things like killall
when things get out of hand. But even if there was, this is still the wrong
approach -- your start-stop-daemon command is sort of equivalent to killall,
which is a really blunt instrument.

···

On Friday 11 December 2009 04:34:04 pm Iñaki Baz Castillo wrote:

Iñaki Baz Castillo wrote:

So, is there some way to force the process to appear as "rb_program" in
/proc/PID/status?

Have you tried

  $0 = 'rb_program'

?

You may find there's a problem if your program name is longer than some
hard-coded limit. There is a workaround at
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/336743

At the top of your program put:

$progname = $0
alias $PROGRAM_NAME $0
alias $0 $progname
trace_var(:$0) {|val| $PROGRAM_NAME = val} # update for ps

···

--
Posted via http://www.ruby-forum.com/.

> So I cannot use "start-stop-daemon --stop --name rb_program" because it
> would find no process names "rb_program"

This is probably not a good idea in the first place -- it means you can't
have separate copies of the program running, and start/stop them
independently, to say nothing of the possibility that some other program
might share the same name.

Since you're using start-stop-daemon anyway, why don't you make a pidfile?

start-stop-daemon --start --startas /home/ibc/rb_program --make-pidfile --
pidfile /var/run/rb_program.pid --background

If your program is backgrounding itself already, configure it to create its
own pidfile -- shouldn't be too hard. Then you can do this instead:

start-stop-daemon --stop --pidfile /var/run/rb_program.pid

Yes, in fact I use it now: my Ruby server creates a pidfile.

The good point of using:

  start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name rb_program

is that it would stop the process just if it's called "rb_program" and its pid
matches the value of /var/run/rb_program.pid, so you cannot kill any other
process using that pid by accident (it could occur if your program didn't
delete the pidfile and a new process has taken same pid value).

···

El Sábado, 12 de Diciembre de 2009, David Masover escribió:

> So, is there some way to force the process to appear as "rb_program" in
> /proc/PID/status?

I'd like to know that, too, because it'd be useful for things like killall
when things get out of hand. But even if there was, this is still the wrong
approach -- your start-stop-daemon command is sort of equivalent to
killall, which is a really blunt instrument.

--
Iñaki Baz Castillo <ibc@aliax.net>

Brian Candler wrote:

Iñaki Baz Castillo wrote:

So, is there some way to force the process to appear as "rb_program" in
/proc/PID/status?

Have you tried

  $0 = 'rb_program'

?

... or I can't remember the details, but perhaps you needed
$0.replace('rb_program'), but that doesn't work for newer versions of
Ruby where $0 is a frozen string, hence the required special code:

···

$progname = $0
alias $PROGRAM_NAME $0
alias $0 $progname
trace_var(:$0) {|val| $PROGRAM_NAME = val} # update for ps

--
Posted via http://www.ruby-forum.com/.

That's a good point -- though I would guess that in theory, it shouldn't be
possible for a program to die in such a way that it wouldn't be able to delete
that file. The only thing that would make sense is a reboot, and on my system,
/var/run is a tmpfs (only exists in RAM/swap), so it's not stored anywhere
that would survive a reboot.

I can think of a few other possibilities, like checking directly (with fuser,
for example) which process is controlling the resource your daemon is
associated with, or even talking to the old daemon over a socket, or some sort
of formal IPC like dbus.

I'm not sure about Debian, but on Ubuntu, the upstart system might also be
worth looking into.

I did find a solution, though:

#!/usr/bin/env ruby

doesn't work. However:

#!/usr/bin/ruby1.9.1

produces a process which responds both to killall and to 'start-stop-daemon --
stop --name'. But hardcoding the location of the Ruby interpreter is
antisocial, especially when there are so many of them. The whole point of env
is that I can always override PATH and point to a different Ruby interpreter,
to easily switch between 1.8, 1.9, JRuby, Rubinius, etc.

I thought I'd found a workaround, and I've been getting messy with C trying to
figure out how to replace env with a more appropriate program, but I'm not
sure how to change the program name at all. That is, this isn't a Ruby issue,
it's a Linux/Unix issue. The best I could figure out was this:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  if (argc == 1) {
    fprintf(stderr, "Usage: %s PROGRAM ARGUMENTS\n", argv[0]);
    return 1;
  }

  char * filename = argv[1];
  argv[1] = "foo";

    execvp(filename, argv+1);

  char * outstr = malloc(strlen(argv[0]) + strlen(argv[1]) + 2);
  sprintf(outstr, "%s: %s", argv[0], argv[1]);
  perror(outstr);
  return errno;
}

Compile that, then change the Ruby script to be:

#!/path/to/that/binary ruby

The same should work for Python.

Except it doesn't.

It does indeed change the program name in /proc/self/cmdline -- it becomes
'foo /name/of/my/program.rb'. And killall and start-stop-daemon both seem to
work, here, but only when I give them "ruby" as the name of the program to
kill.

Notice, also, I'm explicitly setting 'foo' as the program name. If this
worked, I'd detect that dynamically -- but it doesn't.

At this point, I'm about ready to write a script that would copy your script
(or create a wrapper for your script) and change the shebang to match `which
ruby` at the point of invocation, but that wouldn't work either -- that will
fool the program name in /proc, but it won't fool your program -- there's $0
and probably a dozen other things I haven't thought of to tell it that it's
being loaded by a separate script.

I don't really know what else to try. /proc/self/exe is no help; that points
to the Ruby binary no matter what. You might write your own script that greps
through /proc/*/cmdline, but I don't see a way to fool start-stop-daemon
without changing to #!/usr/bin/ruby1.9.1.

···

On Friday 11 December 2009 05:33:06 pm Iñaki Baz Castillo wrote:

The good point of using:

  start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
rb_program

is that it would stop the process just if it's called "rb_program" and its
pid matches the value of /var/run/rb_program.pid, so you cannot kill any
other process using that pid by accident (it could occur if your program
didn't delete the pidfile and a new process has taken same pid value).

Thanks a lot, it sounds really interesting.

However all the above works for me just by adding at the top:
   $0 = "rb_program"
or:
  $PROGRAM_NAME = "rb_program"

With it when I do a "ps" I see "rb_program" which is great.

However in /proc/PID/status I still have the same described issues: "Name:
ruby1.9", so I cannot do "killall rb_program".

This can be solved by using:
  #!/usr/local/bin/ruby1.9
rather than:
  #!/usr/bin/env ruby1.9

but of course hardcoding the location of ruby is not very good approach
(specially when you want your code to run on any Linux system).

Thanks a lot.

···

El Sábado, 12 de Diciembre de 2009, Brian Candler escribió:

Brian Candler wrote:
> Iñaki Baz Castillo wrote:
>> So, is there some way to force the process to appear as "rb_program" in
>> /proc/PID/status?
>
> Have you tried
>
> $0 = 'rb_program'
>
> ?

... or I can't remember the details, but perhaps you needed
$0.replace('rb_program'), but that doesn't work for newer versions of

Ruby where $0 is a frozen string, hence the required special code:
> $progname = $0
> alias $PROGRAM_NAME $0
> alias $0 $progname
> trace_var(:$0) {|val| $PROGRAM_NAME = val} # update for ps

--
Iñaki Baz Castillo <ibc@aliax.net>

> The good point of using:
>
> start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
> rb_program
>
> is that it would stop the process just if it's called "rb_program" and
> its pid matches the value of /var/run/rb_program.pid, so you cannot kill
> any other process using that pid by accident (it could occur if your
> program didn't delete the pidfile and a new process has taken same pid
> value).

That's a good point -- though I would guess that in theory, it shouldn't be
possible for a program to die in such a way that it wouldn't be able to
delete that file. The only thing that would make sense is a reboot, and on
my system, /var/run is a tmpfs (only exists in RAM/swap), so it's not
stored anywhere that would survive a reboot.

Well, usually daemons are coded to deelte the pidfile upon receipt of a SIGINT
signal (or some others). But if the daemon is killed with "kill -9 PID" then
it terminates inmediately without deleting the piddile.

In the case of a crash or segmentfault the daemon wouldn't delete the pidfile
again.

I've coded my Debian init script "start" action so it deletes the existing
"pidfile" if it exists (it shouldn't).

I can think of a few other possibilities, like checking directly (with
fuser, for example) which process is controlling the resource your daemon
is associated with, or even talking to the old daemon over a socket, or
some sort of formal IPC like dbus.

Sounds interesting, but perhaps a bit complex. I think I don't need so much as
there will be an unique instance of the ruby program running in the server.

I did find a solution, though:

#!/usr/bin/env ruby

doesn't work. However:

#!/usr/bin/ruby1.9.1

produces a process which responds both to killall and to 'start-stop-daemon
-- stop --name'.

Great! this is the point. I've checked the daemon in python and it uses
"/usr/bin/python" rather than "/usr/bin/env python".

But hardcoding the location of the Ruby interpreter is
antisocial, especially when there are so many of them. The whole point of
env is that I can always override PATH and point to a different Ruby
interpreter, to easily switch between 1.8, 1.9, JRuby, Rubinius, etc.

Yes, and when dealing with compiled sources rather than linux distribution
specific packages we could have ruby1.9 binay in /usr/local/bin/, /opt/bin/...
I agree 100%. I wouldn't like to hardcode the ruby location.
  

I thought I'd found a workaround, and I've been getting messy with C trying
to figure out how to replace env with a more appropriate program, but I'm
not sure how to change the program name at all. That is, this isn't a Ruby
issue, it's a Linux/Unix issue. The best I could figure out was this:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  if (argc == 1) {
    fprintf(stderr, "Usage: %s PROGRAM ARGUMENTS\n", argv[0]);
    return 1;
  }

  char * filename = argv[1];
  argv[1] = "foo";

    execvp(filename, argv+1);

  char * outstr = malloc(strlen(argv[0]) + strlen(argv[1]) + 2);
  sprintf(outstr, "%s: %s", argv[0], argv[1]);
  perror(outstr);
  return errno;
}

Compile that, then change the Ruby script to be:

#!/path/to/that/binary ruby

The same should work for Python.

Except it doesn't.

It does indeed change the program name in /proc/self/cmdline -- it becomes
'foo /name/of/my/program.rb'. And killall and start-stop-daemon both seem
to work, here, but only when I give them "ruby" as the name of the program
to kill.

Notice, also, I'm explicitly setting 'foo' as the program name. If this
worked, I'd detect that dynamically -- but it doesn't.

At this point, I'm about ready to write a script that would copy your
script (or create a wrapper for your script) and change the shebang to
match `which ruby` at the point of invocation, but that wouldn't work
either -- that will fool the program name in /proc, but it won't fool your
program -- there's $0 and probably a dozen other things I haven't thought
of to tell it that it's being loaded by a separate script.

I don't really know what else to try. /proc/self/exe is no help; that
points to the Ruby binary no matter what. You might write your own script
that greps through /proc/*/cmdline, but I don't see a way to fool
start-stop-daemon without changing to #!/usr/bin/ruby1.9.1.

Thanks a lot for all your suggestions, it's a really interesting subject.
However I would prefer to keep the code as simple as possible. The only I
wanted was the possibility of kill my program using "killall rb_program".

To summarize this is possible in these cases:

a) Hardcoding the ruby location (avoiding using "env").
Not user-friendly.

b) Creating a link "rb_program" to ruby interpreter and invoke my program with
"rb_program /PATH_TO_rb_program.rb".
Not very beauty :slight_smile:

c) Replacing env with your above suggestion.
It involves compiling a C program, it could break something in a not pure
Linux environment...

Well, I've learnt *a lot* in this thread but at this point I think is better
just to leave the code as it is.
Really thanks a lot.

···

El Sábado, 12 de Diciembre de 2009, David Masover escribió:

On Friday 11 December 2009 05:33:06 pm Iñaki Baz Castillo wrote:

--
Iñaki Baz Castillo <ibc@aliax.net>

It seems to be more a "killall" issue since "pidof rb_program" works while
"killall rb_program" not.

···

El Sábado, 12 de Diciembre de 2009, Iñaki Baz Castillo escribió:

However in /proc/PID/status I still have the same described issues: "Name:
ruby1.9", so I cannot do "killall rb_program".

--
Iñaki Baz Castillo <ibc@aliax.net>

Iñaki Baz Castillo:

However in /proc/PID/status I still have the same described
issues: "Name: ruby1.9", so I cannot do "killall rb_program".

This can be solved by using:
  #!/usr/local/bin/ruby1.9
rather than:
  #!/usr/bin/env ruby1.9

but of course hardcoding the location of ruby is not very good
approach (specially when you want your code to run on any Linux
system).

I was wondering about exactly this problem recently. I’m using
hand-rolled Ruby 1.9.1 and 1.8.7 versions in ~/opt – and once I finally
got to rolling my own gem I found out that when RubyGems install an
executable, they put a wrapper script in the given Ruby installation
path, with the hashbang hardcoded to that interpreter’s binary.

In other words – while the executables in my repo start with
‘#!/usr/bin/env ruby’ (and so pick up the ‘current’ Ruby interpreter),
once I roll and install a gem RubyGems create a custom executable
wrappers for them, and the ones installed with Ruby 1.9.1 start with
‘#!/home/shot/opt/ruby-1.9.1-p376/bin/ruby’ (and if I link them from
my ~/bin I don’t even need to do any $PATH munging to get them running
through a given Ruby binary).

Hence, my conclusion is that if you turned your code into a gem prior
to installing it, you could still keep the ‘#!/usr/bin/env ruby1.9’
hashbang in your repo (and for testing), but once you want to get
a given version into ‘production’, RubyGems will turn that into
‘#!/usr/local/bin/ruby1.9’ upon the gem’s installation.

— Shot

···

--
I should like to find the person who decided that since
‘bookmarks’ and ‘history’ were both lists of URLs they
ought to be integrated in a single database. I should like
to shake him warmly by the throat until his head comes off.
             [Roger Burton West on Firefox, hates-software]

I read in http://psmisc.sourceforge.net/changelog.html:

···

El Sábado, 12 de Diciembre de 2009, Iñaki Baz Castillo escribió:

El Sábado, 12 de Diciembre de 2009, Iñaki Baz Castillo escribió:
> However in /proc/PID/status I still have the same described issues:
> "Name: ruby1.9", so I cannot do "killall rb_program".

It seems to be more a "killall" issue since "pidof rb_program" works while
"killall rb_program" not.

----------
Changes from version 12 to 13 (16-APR-1997)

killall: now lists PIDs if invoked as "pidof" (proposed by Peter Daum)
---------

This, if I do "killall rb_" and pres TAB (I've autocompletion) I get "killall
rb_program" but it doesn't work, it doesn't kill the process.
However if I do "pidof rb_program" I get its pid.

Strange... I'll report a bug in psmisc.

--
Iñaki Baz Castillo <ibc@aliax.net>

The good point of using:

  start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
rb_program

is that it would stop the process just if it's called "rb_program" and
its pid matches the value of /var/run/rb_program.pid, so you cannot kill
any other process using that pid by accident (it could occur if your
program didn't delete the pidfile and a new process has taken same pid
value).

That's a good point -- though I would guess that in theory, it shouldn't be
possible for a program to die in such a way that it wouldn't be able to
delete that file. The only thing that would make sense is a reboot, and on
my system, /var/run is a tmpfs (only exists in RAM/swap), so it's not
stored anywhere that would survive a reboot.

Well, usually daemons are coded to deelte the pidfile upon receipt of a SIGINT signal (or some others). But if the daemon is killed with "kill -9 PID" then it terminates inmediately without deleting the piddile.

In the case of a crash or segmentfault the daemon wouldn't delete the pidfile again.

I've coded my Debian init script "start" action so it deletes the existing "pidfile" if it exists (it shouldn't).

You can make deletion conditionally depending on the presence of the process (kill 0). This is what I would do:

VAR='/var/run'

pid_file = File.join(VAR, File.basename($0) + '.pid')

begin
   old_pid = File.read(pid_file).to_i
   Process.kill 0, old_pid
   $stderr.puts "ERROR: already running with PID #{old_pid}"
   exit 1
rescue Errno::ENOENT
   # no pid file
rescue Errno::ESRCH
   # process not running
   $stderr.puts 'WARNING: stale pid file'
end

# open file with EXCL in order to catch race conditions where two
# processes were started almost at the same time and both thought
# they would be a new instance. Uncomment sleep to simulate:
# sleep 2
File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io| io.write($$)}
trap(0) {File.delete pid_file}

puts "OK, here we go."

# just for testing purposes:
File.read(pid_file).to_i == $$ or raise "What went wrong?"

sleep 10

puts "Finished"

Thanks a lot for all your suggestions, it's a really interesting subject.
However I would prefer to keep the code as simple as possible. The only I wanted was the possibility of kill my program using "killall rb_program".

Why does it have to be "killall"? What about providing a command line option "-k" or "--kill" for killing (e.g. as ssh-agent does)? You could integrate that pretty easily with the PID handling code above.

To summarize this is possible in these cases:

a) Hardcoding the ruby location (avoiding using "env").
Not user-friendly.

I personally do not find it too unfriendly to place the interpreter name with an absolute path in the script. This has also greater safety and robustness: the one installing the program and ruby interpreter (some person with administrative permissions) is likely the same and can ensure location is set properly. Relying on users' environments is more fragile IMHO.

b) Creating a link "rb_program" to ruby interpreter and invoke my program with "rb_program /PATH_TO_rb_program.rb".
Not very beauty :slight_smile:

c) Replacing env with your above suggestion.
It involves compiling a C program, it could break something in a not pure Linux environment...

Well, I've learnt *a lot* in this thread but at this point I think is better just to leave the code as it is.
Really thanks a lot.

Well, it's your choice.

Kind regards

  robert

···

On 12.12.2009 10:53, Iñaki Baz Castillo wrote:

El Sábado, 12 de Diciembre de 2009, David Masover escribió:

On Friday 11 December 2009 05:33:06 pm Iñaki Baz Castillo wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Well, usually daemons are coded to deelte the pidfile upon receipt of a
SIGINT signal (or some others). But if the daemon is killed with "kill -9
PID" then it terminates inmediately without deleting the piddile.

True. I tried (and failed) to find an example of this working. However, a
separate process can watch your process and clean up after it however it dies.
I think this is the principle behind letting init handle it -- take "upstart".

In the case of a crash or segmentfault the daemon wouldn't delete the
pidfile again.

If the crash raises an exception, you can catch that. Segmentation faults
trigger SIGSEGV, which you can trap. I suspect you'd have a chance to at least
fire that unlink call with any death except a 'kill -9'.

> I can think of a few other possibilities, like checking directly (with
> fuser, for example) which process is controlling the resource your
> daemon is associated with, or even talking to the old daemon over a
> socket, or some sort of formal IPC like dbus.

Sounds interesting, but perhaps a bit complex. I think I don't need so much
as there will be an unique instance of the ruby program running in the
server.

Yes, probably too complex to do for a specific program. However, it might be
worth wrapping into a library, if there isn't already one designed for this.

Thanks a lot for all your suggestions, it's a really interesting subject.
However I would prefer to keep the code as simple as possible. The only I
wanted was the possibility of kill my program using "killall rb_program".

To summarize this is possible in these cases:

a) Hardcoding the ruby location (avoiding using "env").
Not user-friendly.

However, if you distribute your app as a gem, this problem actually goes away.
Here's the top of gems/rake-0.8.7/bin/rake:

#!/usr/bin/env ruby

···

On Saturday 12 December 2009 03:53:06 am Iñaki Baz Castillo wrote:

#--
# Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
...

Here's what it actually installs into your PATH:

#!/usr/bin/ruby1.9.1
#
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version = ">= 0"

if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end

gem 'rake', version
load Gem.bin_path('rake', 'rake', version)

So, that gives you the best of both worlds -- it's actually somewhat like one
of the crazier solutions I suggested.

b) Creating a link "rb_program" to ruby interpreter and invoke my program
with "rb_program /PATH_TO_rb_program.rb".
Not very beauty :slight_smile:

c) Replacing env with your above suggestion.

Except (c) doesn't work. I thought it would work, and I posted it to the list
in case I was close enough for someone to pick up where I left off.

It involves compiling a C program, it could break something in a not pure
Linux environment...

Well, the idea was that if this worked, it'd be generally useful. After all,
env is on every system, and many Ruby scripts rely on that. So again, not
something specific to your program.

Iñaki Baz Castillo:
> However in /proc/PID/status I still have the same described
> issues: "Name: ruby1.9", so I cannot do "killall rb_program".
>
> This can be solved by using:
> #!/usr/local/bin/ruby1.9
> rather than:
> #!/usr/bin/env ruby1.9
>
> but of course hardcoding the location of ruby is not very good
> approach (specially when you want your code to run on any Linux
> system).

I was wondering about exactly this problem recently. I’m using
hand-rolled Ruby 1.9.1 and 1.8.7 versions in ~/opt – and once I finally
got to rolling my own gem I found out that when RubyGems install an
executable, they put a wrapper script in the given Ruby installation
path, with the hashbang hardcoded to that interpreter’s binary.

I suffer same issues. I've installed ruby 1.9.1 (installed from sources) under
/usr/local. and ruby 1.8.7 (Debian package) under /usr.

I compile ruby1.9 with these options:
  /configure --prefix=/usr/local/ --program-suffix=1.9 ; make ; make install
so all its runnable files are sufixed by 1.9 (ruby1.9, gem1.9, irb1.9...).

Unfortunatelly executables installed by gems are not sufixed so there is
conflict between ruby1.8 gems and ruby1.9 gems.

By default /usr/local/bin/ appears before than /usr/bin/ in usual PATH
environment variable, so executables belonging to ruby1.9 gems take
preference. This is ugly when you install a ruby1.8 gem which requires some
ruby executtable (as racc, rake and so).

So finally my "solution/workaround" is a script that rewrites the PATH
variable and sets /usr/bin/ before /usr/local/bin/. And I must run it before
installing a gem for ruby1.8. Ugly but works :slight_smile:

In other words – while the executables in my repo start with
‘#!/usr/bin/env ruby’ (and so pick up the ‘current’ Ruby interpreter),
once I roll and install a gem RubyGems create a custom executable
wrappers for them, and the ones installed with Ruby 1.9.1 start with
‘#!/home/shot/opt/ruby-1.9.1-p376/bin/ruby’ (and if I link them from
my ~/bin I don’t even need to do any $PATH munging to get them running
through a given Ruby binary).

Hence, my conclusion is that if you turned your code into a gem prior
to installing it, you could still keep the ‘#!/usr/bin/env ruby1.9’
hashbang in your repo (and for testing), but once you want to get
a given version into ‘production’, RubyGems will turn that into
‘#!/usr/local/bin/ruby1.9’ upon the gem’s installation.

Ok, I'll do it.
Thanks a lot.

···

El Sábado, 12 de Diciembre de 2009, Shot (Piotr Szotkowski) escribió:

--
Iñaki Baz Castillo <ibc@aliax.net>

Thanks a lot!

···

El Sábado, 12 de Diciembre de 2009, Robert Klemme escribió:

On 12.12.2009 10:53, Iñaki Baz Castillo wrote:
> El Sábado, 12 de Diciembre de 2009, David Masover escribió:
>> On Friday 11 December 2009 05:33:06 pm Iñaki Baz Castillo wrote:
>>> The good point of using:
>>>
>>> start-stop-daemon --stop --pidfile /var/run/rb_program.pid --name
>>> rb_program
>>>
>>> is that it would stop the process just if it's called "rb_program" and
>>> its pid matches the value of /var/run/rb_program.pid, so you cannot
>>> kill any other process using that pid by accident (it could occur if
>>> your program didn't delete the pidfile and a new process has taken same
>>> pid value).
>>
>> That's a good point -- though I would guess that in theory, it shouldn't
>> be possible for a program to die in such a way that it wouldn't be able
>> to delete that file. The only thing that would make sense is a reboot,
>> and on my system, /var/run is a tmpfs (only exists in RAM/swap), so it's
>> not stored anywhere that would survive a reboot.
>
> Well, usually daemons are coded to deelte the pidfile upon receipt of a
> SIGINT signal (or some others). But if the daemon is killed with "kill -9
> PID" then it terminates inmediately without deleting the piddile.
>
> In the case of a crash or segmentfault the daemon wouldn't delete the
> pidfile again.
>
> I've coded my Debian init script "start" action so it deletes the
> existing "pidfile" if it exists (it shouldn't).

You can make deletion conditionally depending on the presence of the
process (kill 0). This is what I would do:

VAR='/var/run'

pid_file = File.join(VAR, File.basename($0) + '.pid')

begin
   old_pid = File.read(pid_file).to_i
   Process.kill 0, old_pid
   $stderr.puts "ERROR: already running with PID #{old_pid}"
   exit 1
rescue Errno::ENOENT
   # no pid file
rescue Errno::ESRCH
   # process not running
   $stderr.puts 'WARNING: stale pid file'
end

# open file with EXCL in order to catch race conditions where two
# processes were started almost at the same time and both thought
# they would be a new instance. Uncomment sleep to simulate:
# sleep 2
File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|
io.write($$)}
trap(0) {File.delete pid_file}

puts "OK, here we go."

# just for testing purposes:
File.read(pid_file).to_i == $$ or raise "What went wrong?"

sleep 10

puts "Finished"

> Thanks a lot for all your suggestions, it's a really interesting subject.
> However I would prefer to keep the code as simple as possible. The only I
> wanted was the possibility of kill my program using "killall rb_program".

Why does it have to be "killall"? What about providing a command line
option "-k" or "--kill" for killing (e.g. as ssh-agent does)? You could
integrate that pretty easily with the PID handling code above.

> To summarize this is possible in these cases:
>
> a) Hardcoding the ruby location (avoiding using "env").
> Not user-friendly.

I personally do not find it too unfriendly to place the interpreter name
with an absolute path in the script. This has also greater safety and
robustness: the one installing the program and ruby interpreter (some
person with administrative permissions) is likely the same and can
ensure location is set properly. Relying on users' environments is more
fragile IMHO.

> b) Creating a link "rb_program" to ruby interpreter and invoke my program
> with "rb_program /PATH_TO_rb_program.rb".
> Not very beauty :slight_smile:
>
> c) Replacing env with your above suggestion.
> It involves compiling a C program, it could break something in a not pure
> Linux environment...
>
> Well, I've learnt *a lot* in this thread but at this point I think is
> better just to leave the code as it is.
> Really thanks a lot.

Well, it's your choice.

--
Iñaki Baz Castillo <ibc@aliax.net>

> Well, usually daemons are coded to deelte the pidfile upon receipt of a
> SIGINT signal (or some others). But if the daemon is killed with "kill
> -9 PID" then it terminates inmediately without deleting the piddile.

True. I tried (and failed) to find an example of this working. However, a
separate process can watch your process and clean up after it however it
dies. I think this is the principle behind letting init handle it -- take
"upstart".

I should take a deep look to "upstart". Until now I'm just used to usual Linux
init scripts. But since Debian will adopt upstart it's good time to learn it
:slight_smile:

> In the case of a crash or segmentfault the daemon wouldn't delete the
> pidfile again.

If the crash raises an exception, you can catch that.

Yes, I catch all the exceptions, I meant segfaults that can occur when using
Ruby C extensions (or when a Ruby bug occurs).

Segmentation faults
trigger SIGSEGV, which you can trap.

Ops, I didn't know it at all. Really interesting.

I suspect you'd have a chance to at
least fire that unlink call with any death except a 'kill -9'.

Ok, so do you say that using "upstart" this problem could be solved as upstart
itself could manage it when detects a service crash?

> To summarize this is possible in these cases:
>
> a) Hardcoding the ruby location (avoiding using "env").
> Not user-friendly.

However, if you distribute your app as a gem, this problem actually goes
away. Here's the top of gems/rake-0.8.7/bin/rake:

#!/usr/bin/env ruby

#--
# Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
...

Here's what it actually installs into your PATH:

#!/usr/bin/ruby1.9.1
#
# This file was generated by RubyGems.

So, that gives you the best of both worlds -- it's actually somewhat like
one of the crazier solutions I suggested.

Great. However I'm not sure if my program would fit well as a gem. It's not a
library or utility but a whole http server (for XCAP protocol). This is, it
will have conf files into /etc directory and so. I've never seen a gem that
installs a server by itself and contains files in /etc.

Also, I need a Debian init/upstart script so a gem is not fully valid for me.

Thanks a lot for your help.

···

El Sábado, 12 de Diciembre de 2009, David Masover escribió:

On Saturday 12 December 2009 03:53:06 am Iñaki Baz Castillo wrote:

--
Iñaki Baz Castillo <ibc@aliax.net>

Let me a question: is the above a fragment of a Linux init script written in
Ruby (rather than bash/sh as usual)?

If so, according to LSB specifications it should return 0 (success) in case of
"start" action when the daemon is already running.

Thanks a lot.

···

El Sábado, 12 de Diciembre de 2009, Robert Klemme escribió:

This is what I would do:

VAR='/var/run'

pid_file = File.join(VAR, File.basename($0) + '.pid')

begin
   old_pid = File.read(pid_file).to_i
   Process.kill 0, old_pid
   $stderr.puts "ERROR: already running with PID #{old_pid}"
   exit 1
rescue Errno::ENOENT
   # no pid file
rescue Errno::ESRCH
   # process not running
   $stderr.puts 'WARNING: stale pid file'
end

# open file with EXCL in order to catch race conditions where two
# processes were started almost at the same time and both thought
# they would be a new instance. Uncomment sleep to simulate:
# sleep 2
File.open(pid_file, File::EXCL | File::WRONLY | File::CREAT) {|io|
io.write($$)}
trap(0) {File.delete pid_file}

puts "OK, here we go."

--
Iñaki Baz Castillo <ibc@aliax.net>

Iñaki Baz Castillo:

I suffer same issues. I've installed ruby 1.9.1 (installed from
sources) under /usr/local. and ruby 1.8.7 (Debian package) under /usr.

I compile ruby1.9 with these options:
  /configure --prefix=/usr/local/ --program-suffix=1.9 ; make ; make install
so all its runnable files are sufixed by 1.9 (ruby1.9, gem1.9, irb1.9...).

I think a much simpler solutions are to either (a) use rvm (which
doesn’t work for me for some reason) or (b) use my approach (below).

I don’t use program suffixes, but rather use

./configure --prefix=/home/shot/opt/ruby-1.9.1-p376

(and similar, for example ~/opt/ruby-1.8.7-git when building 1.8.7 from
the repo’s latest 1.8.7 revision) plus ~/opt/ruby-1.8 and ~/opt/ruby-1.9
symlinks poiting to the hand-compiled versions I want to use for my
development. I then have

export PATH_ORIG="$PATH"

at the end of my ~/.bashrc and

alias r18='export PATH=/home/shot/opt/ruby-1.8/bin:$PATH_ORIG'
alias r19='export PATH=/home/shot/opt/ruby-1.9/bin:$PATH_ORIG'

in my ~/.bash_aliases, and switching between Ruby 1.8 and 1.9 is as
quick as running ‘r18’ and ‘r19’ in the shell. I leave system-packaged
Ruby alone, if only so that ‘gem update --system’ works sanely (and so
no sudo is required for any of my Ruby development whatsoever).

Of course, if you want to have system-wide hand-compiled Ruby 1.8 and/or
1.9, putting them in /opt (rather than ~/opt) might be more elegant.

— Shot

···

--
We don’t think of ourselves as being perfectionists, really. To us
it’s more about desperately trying to have it sound more or less OK.
                                                      [Donald Fagen]

> I suspect you'd have a chance to at
> least fire that unlink call with any death except a 'kill -9'.

Ok, so do you say that using "upstart" this problem could be solved as
upstart itself could manage it when detects a service crash?

I'm saying most aspects of it can be solved within the program -- anything
except 'kill -9'. With something like upstart, even that should be solvable.
On OS X, I think launchd is similar. Basically, you have one (or more) central
process(es) which manage the launching and killing of daemons.

At this point, you don't even have to use pidfiles, you can just use
variables. In pseudocode:

class Process
  def start
    unless running?
      if @pid = fork
        waitpid(@pid) do
          @pid = nil
        end
      else
        exec @cmdline
      end
    end
  end
  def stop
    kill @pid
  end
end

The main reason that's pseudocode is that upstart very likely already does
this for you (so why reinvent the wheel in Ruby?), and because waitpid doesn't
actually work that way.

But basically, the only problem with this model is that if the process
responsible for watching your process dies abnormally, either the pidfile
won't be cleaned up (if there is one), or you'll now have an unmonitored copy
of your process running (so you'll need something like killall again). If
you're using something like upstart, that's not really a problem -- remember,
upstart is init, which means the second it dies, the kernel panics. In other
words, it doesn't die.

> So, that gives you the best of both worlds -- it's actually somewhat like
> one of the crazier solutions I suggested.

Great. However I'm not sure if my program would fit well as a gem. It's not
a library or utility but a whole http server (for XCAP protocol). This is,
it will have conf files into /etc directory and so. I've never seen a gem
that installs a server by itself and contains files in /etc.

The usual approach I'd suggest here is, store a configfile path, something
like the PATH variable, in which later configfiles override values set by
earlier ones. Then, set all the default values in a sample config file inside
your gem, and let the admin put a conf file in /etc/rb_app (or in ~/.rb_app,
or in a place specified by the environment variable RB_APP_CONFIG, or in a
place specified by --config on the commandline) if they want to override
something.

That just leaves this part:

Also, I need a Debian init/upstart script so a gem is not fully valid for
me.

That much is possibly true -- you'd need a script that installs/updates that
script.

If you're worried about people going so far as to have separate Ruby
interpreters, I'd suggest letting them write their own script, and simply
provide documentation, and maybe a command to install some default samples.
Those scripts would likely be very simple anyway.

On the other hand, you might consider just building a Debian package,
depending on the interpreter you want, and hardcoding it into the shebang and
the upstart scripts. Let people download the source if they want to tweak it
further. But I'd only go this route if you're content to depend on the Ruby
libraries that are already packaged in Debian -- unlike some other package
managers, apt lacks a way to depend directly on truly alien packages.
(Contrast to Gobo, in which system packages can depend directly on gems, CPAN
modules, etc -- I know Gentoo could depend on CPAN modules, too.)

···

On Saturday 12 December 2009 03:54:00 pm Iñaki Baz Castillo wrote:

El Sábado, 12 de Diciembre de 2009, David Masover escribió: