# File lib/fpm/util.rb, line 103
  def execmd(*args)
    i = 0
    if i < args.size
      if args[i].kind_of?(Hash)
        # args[0] may contain environment variables
        env = args[i]
        i += 1
      else
        env = Hash[]
      end
    end

    if i < args.size
      if args[i].kind_of?(Array)
        args2 = args[i]
      else
        args2 = [ args[i] ]
      end
      program = args2[0]
      i += 1
    else
      raise ArgumentError.new("missing argument: cmd")
    end

    if i < args.size
      if args[i].kind_of?(Hash)
        opts = Hash[args[i].map {|k,v| [k.to_sym, v]} ]
        i += 1
      end
    else
      opts = Hash[]
    end

    opts[:process] = false unless opts.include?(:process)
    opts[:stdin]   = true  unless opts.include?(:stdin)
    opts[:stdout]  = true  unless opts.include?(:stdout)
    opts[:stderr]  = true  unless opts.include?(:stderr)

    if !program.include?("/") and !program_in_path?(program)
      raise ExecutableNotFound.new(program)
    end

    logger.debug("Running command", :args => args2)

    stdout_r, stdout_w = IO.pipe
    stderr_r, stderr_w = IO.pipe

    process = ChildProcess.build(*args2)
    process.environment.merge!(env)

    process.io.stdout = stdout_w
    process.io.stderr = stderr_w

    if block_given? and opts[:stdin]
      process.duplex = true
    end

    process.start

    stdout_w.close; stderr_w.close
    logger.debug("Process is running", :pid => process.pid)
    if block_given?
      args3 = []
      args3.push(process)           if opts[:process]
      args3.push(process.io.stdin)  if opts[:stdin]
      args3.push(stdout_r)          if opts[:stdout]
      args3.push(stderr_r)          if opts[:stderr]

      yield(*args3)

      process.io.stdin.close        if opts[:stdin] and not process.io.stdin.closed?
      stdout_r.close                unless stdout_r.closed?
      stderr_r.close                unless stderr_r.closed?
    else
      # Log both stdout and stderr as 'info' because nobody uses stderr for
      # actually reporting errors and as a result 'stderr' is a misnomer.
      logger.pipe(stdout_r => :info, stderr_r => :info)
    end

    process.wait if process.alive?

    return process.exit_code
  end