<commit_before>require 'fileutils'

module God
  class Process
    WRITES_PID = [:start, :restart]
    
    attr_accessor :name, :uid, :gid, :log, :start, :stop, :restart
    
    def initialize
      self.log = '/dev/null'
      
      @pid_file = nil
      @tracking_pid = true
    end
    
    def alive?
      begin
        pid = File.read(self.pid_file).strip.to_i
        System::Process.new(pid).exists?
      rescue Errno::ENOENT
        false
      end
    end
    
    def file_writable?(file)
      pid = fork do
        ::Process::Sys.setgid(Etc.getgrnam(self.gid).gid) if self.gid
        ::Process::Sys.setuid(Etc.getpwnam(self.uid).uid) if self.uid
        
        File.writable?(file) ? exit(0) : exit(1)
      end
      
      wpid, status = ::Process.waitpid2(pid)
      status.exitstatus == 0 ? true : false
    end
    
    def valid?
      # determine if we're tracking pid or not
      self.pid_file
      
      valid = true
      
      # a start command must be specified
      if self.start.nil?
        valid = false
        LOG.log(self, :error, "No start command was specified")
      end
      
      # self-daemonizing processes must specify a stop command
      if !@tracking_pid && self.stop.nil?
        valid = false
        LOG.log(self, :error, "No stop command was specified")
      end
      
      # uid must exist if specified
      if self.uid
        begin
          Etc.getpwnam(self.uid)
        rescue ArgumentError
          valid = false
          LOG.log(self, :error, "UID for '#{self.uid}' does not exist")
        end
      end
      
      # gid must exist if specified
      if self.gid
        begin
          Etc.getgrnam(self.gid)
        rescue ArgumentError
          valid = false
          LOG.log(self, :error, "GID for '#{self.gid}' does not exist")
        end
      end
      
      # pid dir must exist if specified
      if !@tracking_pid && !File.exist?(File.dirname(self.pid_file))
        valid = false
        LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' does not exist")
      end
      
      # pid dir must be writable if specified
      if !@tracking_pid && !file_writable?(File.dirname(self.pid_file))
        valid = false
        LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' is not writable by #{self.uid || Etc.getlogin}")
      end
      
      # log dir must exist if specified
      if self.log && !File.exist?(File.dirname(self.log))
        valid = false
        LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' does not exist")
      end
      
      # log dir must be writable if specified
      if self.log && !file_writable?(File.dirname(self.log))
        valid = false
        LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' is not writable by #{self.uid || Etc.getlogin}")
      end
      
      valid
    end
    
    # DON'T USE THIS INTERNALLY. Use the instance variable. -- Kev
    # No really, trust me. Use the instance variable.
    def pid_file=(value)
      # if value is nil, do the right thing
      if value
        @tracking_pid = false
      else
        @tracking_pid = true
      end
      
      @pid_file = value
    end<commit_msg>fix log file permission check<commit_after>require 'fileutils'

module God
  class Process
    WRITES_PID = [:start, :restart]
    
    attr_accessor :name, :uid, :gid, :log, :start, :stop, :restart
    
    def initialize
      self.log = '/dev/null'
      
      @pid_file = nil
      @tracking_pid = true
      @user_log = false
    end
    
    def alive?
      begin
        pid = File.read(self.pid_file).strip.to_i
        System::Process.new(pid).exists?
      rescue Errno::ENOENT
        false
      end
    end
    
    def file_writable?(file)
      pid = fork do
        ::Process::Sys.setgid(Etc.getgrnam(self.gid).gid) if self.gid
        ::Process::Sys.setuid(Etc.getpwnam(self.uid).uid) if self.uid
        
        File.writable?(file) ? exit(0) : exit(1)
      end
      
      wpid, status = ::Process.waitpid2(pid)
      status.exitstatus == 0 ? true : false
    end
    
    def valid?
      # determine if we're tracking pid or not
      self.pid_file
      
      valid = true
      
      # a start command must be specified
      if self.start.nil?
        valid = false
        LOG.log(self, :error, "No start command was specified")
      end
      
      # self-daemonizing processes must specify a stop command
      if !@tracking_pid && self.stop.nil?
        valid = false
        LOG.log(self, :error, "No stop command was specified")
      end
      
      # uid must exist if specified
      if self.uid
        begin
          Etc.getpwnam(self.uid)
        rescue ArgumentError
          valid = false
          LOG.log(self, :error, "UID for '#{self.uid}' does not exist")
        end
      end
      
      # gid must exist if specified
      if self.gid
        begin
          Etc.getgrnam(self.gid)
        rescue ArgumentError
          valid = false
          LOG.log(self, :error, "GID for '#{self.gid}' does not exist")
        end
      end
      
      # pid dir must exist if specified
      if !@tracking_pid && !File.exist?(File.dirname(self.pid_file))
        valid = false
        LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' does not exist")
      end
      
      # pid dir must be writable if specified
      if !@tracking_pid && !file_writable?(File.dirname(self.pid_file))
        valid = false
        LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' is not writable by #{self.uid || Etc.getlogin}")
      end
      
      # log dir must exist
      if !File.exist?(File.dirname(self.log))
        valid = false
        LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' does not exist")
      end
      
      # log file or dir must be writable
      if File.exist?(self.log)
        unless file_writable?(self.log)
          valid = false
          LOG.log(self, :error, "Log file '#{self.log}' exists but is not writable by #{self.uid || Etc.getlogin}")
        end
      else
        unless file_writable?(File.dirname(self.log))
          valid = false
          LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' is not writable by #{self.uid || Etc.getlogin}")
        end
      end
      
      valid
    end
    
    # DON'T USE THIS INTERNALLY. Use the instance variable. -- Kev
    # No really, trust me. Use the instance variable.
    def pid_file=(value)
      # if value is nil, do the right thing
      if value
        @tracking_pid = false
      else
        @tracking_pid = true
      end
      
      @pid_file = value
    end
{'fraction_non_alphanumeric': 0.1050126431652536, 'fraction_numerical': 0.0011899449650453666, 'mean_word_length': 1.8796573875802998, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6229581', 'n_tokens_mistral': 2107, 'n_tokens_neox': 2089, 'n_words': 595}