/[pupa]/bugcomm/src/bugcommd.in
ViewVC logotype

Diff of /bugcomm/src/bugcommd.in

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by okuji, Wed Aug 14 13:03:38 2002 UTC revision 1.3 by okuji, Wed Aug 14 15:52:58 2002 UTC
# Line 24  require 'mysql' Line 24  require 'mysql'
24  require 'drb/drb'  require 'drb/drb'
25  require 'acl'  require 'acl'
26  require 'cgi'  require 'cgi'
27    require 'syslog'
28    
29  # Define the method `shadow=' specific to $stdin, to hide a password.  # Define the method `shadow=' specific to $stdin, to hide a password.
30  begin  begin
# Line 43  rescue LoadError Line 44  rescue LoadError
44    end    end
45  end  end
46    
47  # Define some classes under the module `BugCommunicator'.  # The master class.
48  module BugCommunicator  class BugCommunicator
49    
50      # Class variables.
51      @@verbosity = 0
52      @@log = $stderr
53      
54      # Exceptions.
55    class BugCommError < Exception; end    class BugCommError < Exception; end
56    
57      # Helper functions.
58      def self.error(str)
59        if @@log.respond_to?(:err)
60          @@log.err('%s', str)
61        elsif @@log.respond_to?(:puts)
62          @@log.puts("bugcommd [#{Process.pid}]: error: #{str}")
63        end
64      end
65    
66      def self.info(str)
67        if @@verbosity > 0
68          if @@log.respond_to?(:info)
69            @@log.info('%s', str)
70          elsif @@log.respond_to?(:puts)
71            @@log.puts("bugcommd [#{Process.pid}]: info: #{str}")
72          end
73        end
74      end
75    
76      def self.debug(str)
77        if @@verbosity > 1
78          if @@log.respond_to?(:debug)
79            @@log.debug('%s', str)
80          elsif @@log.respond_to?(:puts)
81            @@log.puts("bugcommd [#{Process.pid}]: debug: #{str}")
82          end
83        end
84      end
85    
86      def self.clean_up
87        @@log.close if @@log != $stderr
88        @@log = $stderr
89      end
90      # End of helper functions.
91        
92    # Configuration Manager.    # Configuration Manager.
93    class Config    class Config
# Line 196  module BugCommunicator Line 237  module BugCommunicator
237      private :u      private :u
238    
239      def error_log(exception)      def error_log(exception)
240        error("#{exception.message} (#{exception.class})\n" +        error("#{exception.message} (#{exception.class})")
241              exception.backtrace.join("\n"))        exception.backtrace.each do |s|
242            error(s)
243          end
244      end      end
245      private :error_log      private :error_log
246            
# Line 235  module BugCommunicator Line 278  module BugCommunicator
278      end      end
279    end    end
280    # End of class Command.    # End of class Command.
     
 end  
281    
282  # Constants.    def initialize
283  BUGCOMM_VERSION = '@VERSION@'      @config_file = '@BUGCOMMD_CONFIG_FILE@'
284        @log_file = nil
285        @pid_file = nil
286        @passwd = nil
287        @ask_passwd = false
288        @daemonized = false
289    
290        parser = GetoptLong.new
291        parser.set_options(['--help',      '-h', GetoptLong::NO_ARGUMENT],
292                           ['--version',   '-V', GetoptLong::NO_ARGUMENT],
293                           ['--config',    '-c', GetoptLong::REQUIRED_ARGUMENT],
294                           ['--log',       '-l', GetoptLong::REQUIRED_ARGUMENT],
295                           ['--daemon',    '-d', GetoptLong::NO_ARGUMENT],
296                           ['--pid-file',  '-p', GetoptLong::REQUIRED_ARGUMENT],
297                           ['--password',  '-P', GetoptLong::OPTIONAL_ARGUMENT],
298                           ['--verbose',   '-v', GetoptLong::NO_ARGUMENT])
299        # FIXME: should catch errors gracefully.
300        parser.each do |name, arg|
301          case name
302          when '--help'
303            puts 'Usage: bugcommd [OPTION]...'
304            puts ''
305            puts 'BugCommunicator server.'
306            puts ''
307            puts '    -c, --config=FILE        use FILE as a configuration file'
308            puts '    -d, --daemon             run as a daemon'
309            puts '    -h, --help               display this help and exit'
310            puts '    -p, --pid=FILE           write a process id to FILE'
311            puts '    -P, --password[=PASSWD]  set the database password'
312            puts '    -l, --log=FILE           write log messages to FILE'
313            puts '    -v, --verbose            print verbose messages'
314            puts '    -V, --version            print version information and exit'
315            puts ''
316            puts 'Report bugs to <okuji@enbug.org>.'
317            exit 0
318          when '--version'
319            puts "bugcommd (BugCommunicator @VERSION@)"
320            exit 0
321          when '--verbose'
322            @@verbosity += 1
323          when '--config'
324            @config_file = File.expand_path(arg)
325          when '--log'
326            @log_file = File.expand_path(arg)
327          when '--daemon'
328            @daemonized = true
329          when '--pid-file'
330            @pid_file = File.expand_path(arg)
331          when '--password'
332            if arg.empty?
333              @ask_passwd = true
334            else
335              @passwd = arg
336            end
337          end
338        end
339        
340        # Initialize the configuration.
341        @config = BugCommunicator::Config.new(@config_file)
342        
343        if @ask_passwd
344          begin
345            $stdin.shadow = true
346            $stderr.print "Password for the database user `#{@config.db_user}': "
347            @passwd = gets.chomp
348            $stderr.print "\n"
349          ensure
350            $stdin.shadow = false
351          end
352        end
353        
354        @config.db_password = @passwd unless @passwd.nil?
355    
356  # Variables.      # Trap some signals.
357  $verbosity = 0      trap(:INT) { handler('SIGINT') }
358  $log = nil      trap(:HUP) { handler('SIGHUP') }
359        trap(:TERM) { handler('SIGTERM') }
360  config_file = '@BUGCOMMD_CONFIG_FILE@'      trap(:USR1, "IGNORE")
361  log_file = nil      trap(:USR2, "IGNORE")
362  pid_file = nil      
363  passwd = nil      # Open the log.
364  ask_passwd = false      if @log_file.nil? and @daemonized
365  daemonized = false        @@log = Syslog.open('bugcommd',
366                              Syslog::Constants::LOG_PID |
367  ## Start the main routine.                            Syslog::Constants::LOG_CONS,
368  # Parse arguments.                            Syslog::Constants::LOG_DAEMON)
 parser = GetoptLong.new  
 parser.set_options(['--help',      '-h', GetoptLong::NO_ARGUMENT],  
                    ['--version',   '-V', GetoptLong::NO_ARGUMENT],  
                    ['--config',    '-c', GetoptLong::REQUIRED_ARGUMENT],  
                    ['--log',       '-l', GetoptLong::REQUIRED_ARGUMENT],  
                    ['--daemon',    '-d', GetoptLong::NO_ARGUMENT],  
                    ['--pid-file',  '-p', GetoptLong::REQUIRED_ARGUMENT],  
                    ['--password',  '-P', GetoptLong::OPTIONAL_ARGUMENT],  
                    ['--verbose',   '-v', GetoptLong::NO_ARGUMENT])  
 # FIXME: should catch errors gracefully.  
 parser.each do |name, arg|  
   case name  
   when '--help'  
     puts 'Usage: bugcommd [OPTION]...'  
     puts ''  
     puts 'BugCommunicator server.'  
     puts ''  
     puts '    -c, --config=FILE        use FILE as a configuration file'  
     puts '    -d, --daemon             run as a daemon'  
     puts '    -h, --help               display this help and exit'  
     puts '    -p, --pid=FILE           write a process id to FILE'  
     puts '    -P, --password[=PASSWD]  set the database password'  
     puts '    -l, --log=FILE           write log messages to FILE'  
     puts '    -v, --verbose            print verbose messages'  
     puts '    -V, --version            print version information and exit'  
     puts ''  
     puts 'Report bugs to <okuji@enbug.org>.'  
     exit 0  
   when '--version'  
     puts "bugcommd (BugCommunicator #{BUGCOMM_VERSION})"  
     exit 0  
   when '--verbose'  
     $verbosity += 1  
   when '--config'  
     config_file = File.expand_path(arg)  
   when '--log'  
     log_file = File.expand_path(arg)  
   when '--daemon'  
     daemonized = true  
   when '--pid-file'  
     pid_file = File.expand_path(arg)  
   when '--password'  
     if arg.empty?  
       ask_passwd = true  
369      else      else
370        passwd = arg        unless @log_file.nil?
371            @@log = File.open(@log_file, 'a')
372          end
373      end      end
374    end    end
 end  
   
 # Initialize the configuration.  
 config = BugCommunicator::Config.new(config_file)  
   
 if ask_passwd  
   begin  
     $stdin.shadow = true  
     $stderr.print "Enter the password for the database user `#{config.db_user}': "  
     passwd = gets.chomp  
     $stderr.print "\n"  
   ensure  
     $stdin.shadow = false  
   end  
 end  
   
 config.db_password = passwd unless passwd.nil?  
   
 # Open the log.  
 if log_file.nil? and daemonized  
   require 'syslog'  
   $log = Syslog.open('bugcommd',  
                     Syslog::Constants::LOG_PID |  
                     Syslog::Constants::LOG_CONS,  
                     Syslog::Constants::LOG_DAEMON)  
 else  
   if log_file.nil?  
     $log = $stderr  
   else  
     $log = File.open(log_file, 'a')  
   end  
     
   def $log.err(str, *args)  
     self.puts("bugcommd [error]: " + sprintf(str, *args))  
   end  
   def $log.info(str, *args)  
     self.puts("bugcommd [info]: " + sprintf(str, *args))  
   end  
   def $log.debug(str, *args)  
     self.puts("bugcommd [debug]: " + sprintf(str, *args))  
   end  
 end  
375    
 at_exit { $log.close }  
   
 def error(str)  
   $log.err('%s', str)  
 end  
   
 def info(str)  
   $log.info('%s', str) if $verbosity > 0  
 end  
   
 def debug(str)  
   $log.debug('%s', str) if $verbosity > 1  
 end  
   
 begin  
376    # Signal handler.    # Signal handler.
377    def handler(sig)    def handler(sig)
378      s = DRb.primary_server      s = DRb.primary_server
# Line 371  begin Line 384  begin
384          next if t == Thread.current or t == Thread.main or t == s.thread          next if t == Thread.current or t == Thread.main or t == s.thread
385          group.add(t)          group.add(t)
386        end        end
387          
388        10.times do |i|        10.times do |i|
389          group.list.each do |t|          group.list.each do |t|
390            t.kill unless t[:critical]            t.kill unless t[:critical]
391          end          end
392            
393          sleep 1 unless group.list.empty?          sleep 1 unless group.list.empty?
394        end        end
395          
396        group.list.each do |t|        group.list.each do |t|
397          t.kill          t.kill
398        end        end
399      end      end
400        
401      info("interrupted by the signal `#{sig}'")      self.class.info("interrupted by the signal `#{sig}'")
402      exit      exit
403    end    end
404                private :handler
   trap(:INT) { handler('SIGINT') }  
   trap(:HUP) { handler('SIGHUP') }  
   trap(:TERM) { handler('SIGTERM') }  
   trap(:USR1, "IGNORE")  
   trap(:USR2, "IGNORE")  
405        
406    # Run as a daemon, if necessary.    # Run itself as a daemon.
407    if daemonized    def daemonize
408      exit! if fork      exit! if fork
409            
410      Process.setsid      Process.setsid
411      if pid = fork      if pid = fork
412        unless pid_file.nil?        unless @pid_file.nil?
413          File.open(pid_file, 'w') do |f|          File.open(@pid_file, 'w') do |f|
414            f.write pid            f.write pid
415          end          end
416        end        end
# Line 415  begin Line 423  begin
423      $stdout.close      $stdout.close
424      $stderr.close      $stderr.close
425    end    end
426      private :daemonize
427      
428      # The main routine.
429      def main
430        begin
431          # Run as a daemon, if necessary.
432          daemonize if @daemonized
433          
434          # Run a dRuby service.
435          acl = ACL.new(@config.acl, ACL::DENY_ALLOW)
436          uri = "druby://#{@config.host}:#{@config.port}"
437          DRb::DRbServer.default_argc_limit(2)
438          unless @config.size_limit.nil?
439            DRb::DRbServer.default_load_limit(@config.size_limit)
440          end
441          DRb::DRbServer.new(uri, Command.new(@config), acl)
442          self.class.info("starting the dRuby service at `#{uri}'")
443          DRb.thread.join
444        rescue BugCommError, NoMemoryError, ScriptError, StandardError => e
445          self.class.error("#{e.message} (#{e.class})")
446          e.backtrace.each do |s|
447            self.class.error(s)
448          end
449        ensure
450          if @pid_file and File.exist?(@pid_file)
451            self.class.info("deleteing the pid file `#{@pid_file}'")
452            File.delete(@pid_file)
453          end
454        end
455      end
456      
457    end
458    
459    # Run a dRuby service.  begin
460    acl = ACL.new(config.acl, ACL::DENY_ALLOW)    BugCommunicator.debug('initializing the server')
461    uri = "druby://#{config.host}:#{config.port}"    bugcomm = BugCommunicator.new
462    begin    BugCommunicator.info('starting the service')
463      s = DRb::DRbServer.new(uri, BugCommunicator::Command.new(config), acl)    bugcomm.main
     s.argc_limit = 2  
     s.load_limit = config.size_limit unless config.size_limit.nil?  
   rescue SignalException, Interrupt  
   end  
   DRb.thread.join  
 rescue BugCommunicator::BugCommError, NoMemoryError,  
     ScriptError, StandardError => e  
   error("#{e.message} (#{e.class})")  
   error(e.backtrace.join("\n"))  
464  ensure  ensure
465    File.delete(pid_file) if pid_file and File.exist?(pid_file)    BugCommunicator.info('stopping the service')
466      BugCommunicator.clean_up
467  end  end

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26