module Eye::System

Public Class Methods

check_pid_alive(pid) click to toggle source

Check that pid really exits very fast return result hash

# File lib/eye/system.rb, line 12
def check_pid_alive(pid)
  res = if pid
    ::Process.kill(0, pid)
  else
    false
  end

  { result: res }
rescue => ex
  { error: ex }
end
daemonize(cmd, cfg = {}) click to toggle source

Daemonize cmd, and detach options:

:pid_file
:working_dir
:environment
:stdin, :stdout, :stderr
# File lib/eye/system.rb, line 63
def daemonize(cmd, cfg = {})
  pid = ::Process.spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))

  { pid: pid, exitstatus: 0 }

rescue Errno::ENOENT, Errno::EACCES => ex
  { error: ex }

ensure
  Process.detach(pid) if pid
end
execute(cmd, cfg = {}) click to toggle source

Execute cmd with blocking, return status (be careful: inside actor blocks it mailbox, use with defer) options

:working_dir
:environment
:stdin, :stdout, :stderr
# File lib/eye/system.rb, line 80
def execute(cmd, cfg = {})
  pid = ::Process.spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))

  timeout = cfg[:timeout] || 1.second
  status = 0

  Timeout.timeout(timeout) do
    _, st = Process.waitpid2(pid)
    status = st.exitstatus || st.termsig
  end

  { pid: pid, exitstatus: status }

rescue Timeout::Error => ex
  if pid
    warn "[#{cfg[:name]}] sending :KILL signal to <#{pid}> due to timeout (#{timeout}s)"
    send_signal(pid, 9)
  end
  { error: ex }

rescue Errno::ENOENT, Errno::EACCES => ex
  { error: ex }

ensure
  Process.detach(pid) if pid
end
normalized_file(file, working_dir = nil) click to toggle source

normalize file

# File lib/eye/system.rb, line 108
def normalized_file(file, working_dir = nil)
  File.expand_path(file, working_dir)
end
pid_alive?(pid) click to toggle source

Check that pid really exits very fast return true/false

# File lib/eye/system.rb, line 27
def pid_alive?(pid)
  if pid
    ::Process.kill(0, pid)
    true
  end
rescue
  false
end
prepare_env(config = {}) click to toggle source
# File lib/eye/system.rb, line 133
def prepare_env(config = {})
  env = {}

  (config[:environment] || {}).each do |k, v|
    env[k.to_s] = v && v.to_s
  end

  env
end
send_signal(pid, code = :TERM) click to toggle source

Send signal to process (uses for kill) code: TERM(15), KILL(9), QUIT(3), …

# File lib/eye/system.rb, line 38
def send_signal(pid, code = :TERM)
  code = 0 if code == '0'
  if code.to_s.to_i != 0
    code = code.to_i
    code = -code if code < 0
  end
  code = code.to_s.upcase if code.is_a?(String) || code.is_a?(Symbol)

  if pid
    ::Process.kill(code, pid)
    { result: :ok }
  else
    { error: Exception.new('no_pid') }
  end

rescue => ex
  { error: ex }
end
spawn_options(config = {}) click to toggle source
# File lib/eye/system.rb, line 112
def spawn_options(config = {})
  options = {
    pgroup: true,
    chdir: config[:working_dir] || '/'
  }

  options[:out]   = [config[:stdout], 'a'] if config[:stdout]
  options[:err]   = [config[:stderr], 'a'] if config[:stderr]
  options[:in]    = config[:stdin] if config[:stdin]
  options[:umask] = config[:umask] if config[:umask]
  options[:close_others] = false if config[:preserve_fds]
  options[:unsetenv_others] = true if config[:clear_env]

  if Eye::Local.root?
    options[:uid] = Etc.getpwnam(config[:uid]).uid if config[:uid]
    options[:gid] = Etc.getgrnam(config[:gid]).gid if config[:gid]
  end

  options
end