module PatchELF::CLI

For command line interface to parsing arguments.

Constants

SCRIPT_NAME

Name of binary.

USAGE

CLI usage string.

Public Instance Methods

work(argv) click to toggle source

Main method of CLI. @param [Array<String>] argv

Command line arguments.

@return [void] @example

PatchELF::CLI.work(%w[--help])
# usage message to stdout
PatchELF::CLI.work(%w[--version])
# version message to stdout
# File lib/patchelf/cli.rb, line 27
def work(argv)
  @options = {
    set: {},
    print: [],
    needed: []
  }
  return $stdout.puts "PatchELF Version #{PatchELF::VERSION}" if argv.include?('--version')
  return $stdout.puts option_parser unless parse(argv)

  # Now the options are (hopefully) valid, let's process the ELF file.
  begin
    @patcher = PatchELF::Patcher.new(@options[:in_file])
  rescue ELFTools::ELFError, Errno::ENOENT => e
    return PatchELF::Logger.error(e.message)
  end
  patcher.use_rpath! if @options[:force_rpath]
  readonly
  patch_requests
  patcher.save(@options[:out_file])
end

Private Instance Methods

option_parser() click to toggle source
# File lib/patchelf/cli.rb, line 83
def option_parser
  @option_parser ||= OptionParser.new do |opts|
    opts.banner = USAGE

    opts.on('--print-interpreter', '--pi', 'Show interpreter\'s name.') do
      @options[:print] << :interpreter
    end

    opts.on('--print-needed', '--pn', 'Show needed libraries specified in DT_NEEDED.') do
      @options[:print] << :needed
    end

    opts.on('--print-runpath', '--pr', 'Show the path specified in DT_RUNPATH.') do
      @options[:print] << :runpath
    end

    opts.on('--print-soname', '--ps', 'Show soname specified in DT_SONAME.') do
      @options[:print] << :soname
    end

    opts.on('--set-interpreter INTERP', '--interp INTERP', 'Set interpreter\'s name.') do |interp|
      @options[:set][:interpreter] = interp
    end

    opts.on('--set-needed LIB1,LIB2,LIB3', '--needed LIB1,LIB2,LIB3', Array,
            'Set needed libraries, this will remove all existent needed libraries.') do |needs|
      @options[:set][:needed] = needs
    end

    opts.on('--add-needed LIB', 'Append a new needed library.') do |lib|
      @options[:needed] << [:add, lib]
    end

    opts.on('--remove-needed LIB', 'Remove a needed library.') do |lib|
      @options[:needed] << [:remove, lib]
    end

    opts.on('--replace-needed LIB1,LIB2', Array, 'Replace needed library LIB1 as LIB2.') do |libs|
      @options[:needed] << [:replace, libs]
    end

    opts.on('--set-runpath PATH', '--runpath PATH', 'Set the path of runpath.') do |path|
      @options[:set][:runpath] = path
    end

    opts.on(
      '--force-rpath',
      'According to the ld.so docs, DT_RPATH is obsolete,',
      "#{SCRIPT_NAME} will always try to get/set DT_RUNPATH first.",
      'Use this option to force every operations related to runpath (e.g. --runpath)',
      'to consider \'DT_RPATH\' instead of \'DT_RUNPATH\'.'
    ) do
      @options[:force_rpath] = true
    end

    opts.on('--set-soname SONAME', '--so SONAME', 'Set name of a shared library.') do |soname|
      @options[:set][:soname] = soname
    end

    opts.on('--version', 'Show current gem\'s version.') {}
  end
end
parse(argv) click to toggle source
# File lib/patchelf/cli.rb, line 74
def parse(argv)
  remain = option_parser.permute(argv)
  return false if remain.first.nil?

  @options[:in_file] = remain.first
  @options[:out_file] = remain[1] # can be nil
  true
end
patch_requests() click to toggle source
# File lib/patchelf/cli.rb, line 64
def patch_requests
  @options[:set].each do |sym, val|
    patcher.__send__("#{sym}=".to_sym, val)
  end

  @options[:needed].each do |type, val|
    patcher.__send__("#{type}_needed".to_sym, *val)
  end
end
patcher() click to toggle source
# File lib/patchelf/cli.rb, line 50
def patcher
  @patcher
end
readonly() click to toggle source
# File lib/patchelf/cli.rb, line 54
def readonly
  @options[:print].uniq.each do |s|
    content = patcher.__send__(s)
    next if content.nil?

    s = :rpath if @options[:force_rpath] && s == :runpath
    $stdout.puts "#{s}: #{Array(content).join(' ')}"
  end
end