Module: PatchELF::CLI

Extended by:
CLI
Included in:
CLI
Defined in:
lib/patchelf/cli.rb

Overview

For command line interface to parsing arguments.

Constant Summary collapse

SCRIPT_NAME =

Name of binary.

'patchelf.rb'
USAGE =

CLI usage string.

format('Usage: %s <commands> FILENAME [OUTPUT_FILE]', SCRIPT_NAME).freeze

Class Method Summary collapse

Class Method Details

.option_parserObject



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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# 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) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
# 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_requestsObject



64
65
66
67
68
69
70
71
72
# File 'lib/patchelf/cli.rb', line 64

def patch_requests
  @options[:set].each do |sym, val|
    patcher.__send__(:"#{sym}=", val)
  end

  @options[:needed].each do |type, val|
    patcher.__send__(:"#{type}_needed", *val)
  end
end

.patcherObject



50
51
52
# File 'lib/patchelf/cli.rb', line 50

def patcher
  @patcher
end

.readonlyObject



54
55
56
57
58
59
60
61
62
# 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

.work(argv) ⇒ void

This method returns an undefined value.

Main method of CLI.

Examples:

PatchELF::CLI.work(%w[--help])
# usage message to stdout
PatchELF::CLI.work(%w[--version])
# version message to stdout

Parameters:

  • argv (Array<String>)

    Command line arguments.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 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