File: Daemon.rb

package info (click to toggle)
tj3 3.8.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,048 kB
  • sloc: ruby: 36,481; javascript: 1,113; sh: 19; makefile: 17
file content (122 lines) | stat: -rw-r--r-- 3,508 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = Daemon.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
#               by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#

require 'taskjuggler/MessageHandler'

class TaskJuggler

  # This class provides the basic functionality to turn the current process
  # into a background process (daemon). To use it, derive you main class from
  # this class and call the start() method.
  class Daemon

    include MessageHandler

    attr_accessor :pidFile, :daemonize

    def initialize
      # You can set this flag to false to prevent the program from
      # disconnecting from the current terminal. This is useful for debugging
      # purposes.
      @daemonize = true
      # Save the PID of the running daemon as number into this file.
      @pidFile = nil
    end

    # Call this method to turn the process into a background process.
    def start
      return 0 unless @daemonize

      # Fork and have the parent exit
      if (pid = fork) == -1
        fatal('first_fork_failed', 'First fork failed')
      elsif !pid.nil?
        # This is the parent. We can exit now.
        debug('', "Forked a child process with PID #{pid}")
        exit! 0
      end

      # Create a new session
      Process.setsid
      # Fork again to make sure we lose the controlling terminal
      if (pid = fork) == -1
        fatal('second_fork_failed', 'Second fork failed')
      elsif !pid.nil?
        # This is the parent. We can exit now.
        debug('', "Forked a child process with PID #{pid}")
        exit! 0
      end

      @pid = Process.pid

      writePidFile

      # Change current working directory to the file system root
      Dir.chdir '/'
      # Make sure we can create files with any permission
      File.umask 0

      # We no longer have a controlling terminal, so these are useless.
      $stdin.reopen('/dev/null')
      $stdout.reopen('/dev/null', 'a')
      $stderr.reopen($stdout)

      info('daemon_pid',
           "The process is running as daemon now with PID #{@pid}")

      0
    end

    # This method may provide some cleanup functionality in the future. You
    # better call it before you exit.
    def stop
      if @pidFile
        begin
          File.delete(@pidFile)
        rescue
          warning('cannot_delete_pidfile',
                  "Cannote delete the PID file (#{@pidFile}): #{$!}")
        end
        info('daemon_deleted_pidfile', "PID file #{@pidFile} deleted")
      end
    end

    private

    def writePidFile
      if @pidFile
        # Prepend the current working dir to @pidFile unless it's already an
        # absolute path. The working dir is changed to '/' later. We need the
        # absolute name to be able to delete it on exit again.
        if @pidFile[0] != '/'
          @pidFile = File.join(Dir.getwd, @pidFile)
        end

        # If requested, write the PID of the daemon to the specified file.
        begin
          File.open(@pidFile, 'w') do |f|
            f.puts @pid
          end
        rescue
          warning('cannot_save_pidfile', "Cannot write PID to #{@pidFile}")
        end
        info('daemon_wrote_pidfile',
             "PID file #{@pidFile} written with PID #{@pid}")
      end

    end

  end

end