sockd 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/sockd/runner.rb +54 -65
- data/lib/sockd/version.rb +1 -1
- data/lib/sockd.rb +167 -23
- metadata +2 -4
- data/lib/sockd/errors.rb +0 -15
- data/lib/sockd/optparse.rb +0 -121
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6eac67e5bf5c221e1246054c67fe114d0e1ce125
|
4
|
+
data.tar.gz: cd0fca78d6544e1b4badca98c291313bb2c3955f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dee986312d3761ef7854df1a6f6937ddf3d3a9a086969ea056ec396334d4fb4f4c7e32bcbc3f94c174e019da22d83cc5e32a0232a40dd21797abfeaa9b2652b
|
7
|
+
data.tar.gz: 92af3f8162ba59946f266c01198c3b4fd08814a4fbba27d1b465989a57b3f1d3f80fbfa19ddfe4f4d6ffd15f4734d07e1916b6ab172f21d315b551e2f21a8bf0
|
data/lib/sockd/runner.rb
CHANGED
@@ -1,22 +1,20 @@
|
|
1
|
-
require "logger"
|
2
1
|
require "socket"
|
3
2
|
require "timeout"
|
4
3
|
require "fileutils"
|
5
|
-
require "sockd/errors"
|
6
4
|
|
7
5
|
module Sockd
|
8
6
|
class Runner
|
9
7
|
|
8
|
+
class ServiceError < RuntimeError; end
|
9
|
+
|
10
10
|
attr_reader :options, :name
|
11
11
|
|
12
12
|
class << self
|
13
|
-
|
14
|
-
self.new(*args, &block)
|
15
|
-
end
|
13
|
+
alias define new
|
16
14
|
end
|
17
15
|
|
18
|
-
def initialize(name, options = {}, &block)
|
19
|
-
@name = name
|
16
|
+
def initialize(name = nil, options = {}, &block)
|
17
|
+
@name = name || File.basename($0)
|
20
18
|
@options = {
|
21
19
|
:host => "127.0.0.1",
|
22
20
|
:port => 0,
|
@@ -66,33 +64,24 @@ module Sockd
|
|
66
64
|
# @runner.handle { |msg| if msg == 'foo' then return 'bar' ... }
|
67
65
|
def handle(message = nil, socket = nil, &block)
|
68
66
|
return self if block_given? && @handle = block
|
69
|
-
|
67
|
+
raise ArgumentError, "no message handler provided" unless @handle
|
70
68
|
@handle.call(message, socket)
|
71
69
|
end
|
72
70
|
|
73
|
-
# call one of start, stop, restart, or send
|
74
|
-
def run(method, *args)
|
75
|
-
if %w(start stop restart send).include?(method)
|
76
|
-
begin
|
77
|
-
self.public_send method.to_sym, *args
|
78
|
-
rescue ArgumentError => e
|
79
|
-
raise unless e.backtrace[1].include? "in `public_send"
|
80
|
-
raise BadCommandError, "wrong number of arguments for command: #{method}"
|
81
|
-
end
|
82
|
-
else
|
83
|
-
raise BadCommandError, "invalid command: #{method}"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
71
|
# start our service
|
88
72
|
def start
|
89
73
|
server do |server|
|
90
74
|
|
91
75
|
if options[:daemonize]
|
92
76
|
pid = daemon_running?
|
93
|
-
raise
|
77
|
+
raise ServiceError, "#{name} process already running (#{pid})" if pid
|
94
78
|
puts "starting #{name} process..."
|
95
|
-
|
79
|
+
unless daemonize
|
80
|
+
unless send('ping', 10).chomp == 'pong'
|
81
|
+
raise ServiceError, "invalid ping response"
|
82
|
+
end
|
83
|
+
return self
|
84
|
+
end
|
96
85
|
end
|
97
86
|
|
98
87
|
drop_privileges options[:user], options[:group]
|
@@ -106,7 +95,8 @@ module Sockd
|
|
106
95
|
exit 130
|
107
96
|
end
|
108
97
|
|
109
|
-
log "listening on
|
98
|
+
log "listening on #{server.local_address.inspect_sockaddr}"
|
99
|
+
|
110
100
|
while true
|
111
101
|
sock = server.accept
|
112
102
|
begin
|
@@ -139,7 +129,7 @@ module Sockd
|
|
139
129
|
Process.kill('KILL', pid)
|
140
130
|
puts "SIGKILL sent to #{name} (#{pid})"
|
141
131
|
end
|
142
|
-
raise
|
132
|
+
raise ServiceError, "unable to stop #{name} process" if daemon_running?
|
143
133
|
else
|
144
134
|
warn "#{name} process not running"
|
145
135
|
end
|
@@ -153,22 +143,16 @@ module Sockd
|
|
153
143
|
end
|
154
144
|
|
155
145
|
# send a message to a running service and return the response
|
156
|
-
def send(
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
sock.write message + "\r\n"
|
163
|
-
response = sock.gets
|
164
|
-
end
|
165
|
-
rescue Errno::ECONNREFUSED, Errno::ENOENT
|
166
|
-
unless daemon_running?
|
167
|
-
abort "#{name} process not running"
|
168
|
-
end
|
169
|
-
abort "unable to establish connection"
|
146
|
+
def send(message, timeout = 30)
|
147
|
+
client do |sock|
|
148
|
+
sock.write "#{message}\r\n"
|
149
|
+
ready = IO.select([sock], nil, nil, timeout)
|
150
|
+
raise ServiceError, "timed out waiting for server response" unless ready
|
151
|
+
sock.recv(256)
|
170
152
|
end
|
171
|
-
|
153
|
+
rescue Errno::ECONNREFUSED, Errno::ENOENT
|
154
|
+
raise ServiceError, "#{name} process not running" unless daemon_running?
|
155
|
+
raise ServiceError, "unable to establish connection"
|
172
156
|
end
|
173
157
|
|
174
158
|
# output a timestamped log message
|
@@ -185,29 +169,23 @@ module Sockd
|
|
185
169
|
UNIXServer.new(options[:socket])
|
186
170
|
rescue Errno::EADDRINUSE
|
187
171
|
begin
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
if sock.gets.chomp == "pong"
|
192
|
-
raise ProcError, "socket #{options[:socket]} already in use by another instance of #{name}"
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
raise ProcError, "socket #{options[:socket]} already in use by another process"
|
197
|
-
rescue Errno::ECONNREFUSED, Timeout::Error
|
172
|
+
send('ping', 20)
|
173
|
+
rescue ServiceError
|
174
|
+
# socket stale, reopening
|
198
175
|
File.delete(options[:socket])
|
199
176
|
UNIXServer.new(options[:socket])
|
177
|
+
else
|
178
|
+
raise ServiceError, "socket #{options[:socket]} already in use by another process"
|
200
179
|
end
|
201
180
|
end.tap do
|
202
181
|
# get user and group ids
|
203
|
-
uid =
|
204
|
-
gid =
|
205
|
-
gid = Etc.getpwnam(options[:user]).gid if !gid && options[:user]
|
182
|
+
uid, gid = user_id(options[:user]) if options[:user]
|
183
|
+
gid = group_id(options[:group]) if options[:group]
|
206
184
|
File.chown(uid, gid, options[:socket]) if uid || gid
|
207
185
|
|
208
186
|
# ensure mode is octal if string provided
|
209
187
|
options[:mode] = options[:mode].to_i(8) if options[:mode].is_a?(String)
|
210
|
-
File.chmod(options[:mode], options[:socket])
|
188
|
+
File.chmod(options[:mode], options[:socket]) if options[:mode] != 0
|
211
189
|
end
|
212
190
|
else
|
213
191
|
TCPServer.new(options[:host], options[:port])
|
@@ -219,7 +197,7 @@ module Sockd
|
|
219
197
|
end
|
220
198
|
rescue Errno::EACCES
|
221
199
|
sock = options[:socket] || "#{options[:host]}:#{options[:port]}"
|
222
|
-
raise
|
200
|
+
raise ServiceError, "unable to open socket: #{sock} (check permissions)"
|
223
201
|
end
|
224
202
|
|
225
203
|
# return a UNIXSocket or TCPSocket instance depending on config
|
@@ -231,7 +209,7 @@ module Sockd
|
|
231
209
|
end
|
232
210
|
rescue Errno::EACCES
|
233
211
|
sock = options[:socket] || "#{options[:host]}:#{options[:port]}"
|
234
|
-
raise
|
212
|
+
raise ServiceError, "unable to open socket: #{sock} (check permissions)"
|
235
213
|
end
|
236
214
|
|
237
215
|
# handle process termination signals
|
@@ -271,7 +249,7 @@ module Sockd
|
|
271
249
|
|
272
250
|
Process.waitpid
|
273
251
|
unless wait_until { daemon_running? }
|
274
|
-
raise
|
252
|
+
raise ServiceError, "failed to start #{name} service"
|
275
253
|
end
|
276
254
|
end
|
277
255
|
|
@@ -291,15 +269,13 @@ module Sockd
|
|
291
269
|
|
292
270
|
# drop privileges to the specified user and group
|
293
271
|
def drop_privileges(user, group)
|
294
|
-
uid =
|
295
|
-
gid =
|
296
|
-
gid = Etc.getpwnam(user).gid if group.nil? && user
|
272
|
+
uid, gid = user_id(user) if user
|
273
|
+
gid = group_id(group) if group
|
297
274
|
|
298
275
|
Process::Sys.setgid(gid) if gid
|
299
276
|
Process::Sys.setuid(uid) if uid
|
300
|
-
rescue
|
301
|
-
|
302
|
-
raise ProcError, "unable to drop privileges (#{e})"
|
277
|
+
rescue Errno::EPERM => e
|
278
|
+
raise ServiceError, "unable to drop privileges (#{e})"
|
303
279
|
end
|
304
280
|
|
305
281
|
# redirect our output as per configuration
|
@@ -329,7 +305,7 @@ module Sockd
|
|
329
305
|
rescue Errno::EACCES, Errno::EISDIR
|
330
306
|
end
|
331
307
|
unless File.file?(path) && File.writable?(path)
|
332
|
-
raise
|
308
|
+
raise ServiceError, "unable to open file: #{path} (check permissions)"
|
333
309
|
end
|
334
310
|
path
|
335
311
|
end
|
@@ -341,5 +317,18 @@ module Sockd
|
|
341
317
|
end
|
342
318
|
timer > 0
|
343
319
|
end
|
320
|
+
|
321
|
+
def user_id(user)
|
322
|
+
user = Etc.getpwnam(user)
|
323
|
+
[user.uid, user.gid]
|
324
|
+
rescue ArgumentError
|
325
|
+
raise ServiceError, "unable to find user: #{user}"
|
326
|
+
end
|
327
|
+
|
328
|
+
def group_id(group)
|
329
|
+
Etc.getgrnam(group).gid
|
330
|
+
rescue ArgumentError
|
331
|
+
raise ServiceError, "unable to find group: #{user}"
|
332
|
+
end
|
344
333
|
end
|
345
334
|
end
|
data/lib/sockd/version.rb
CHANGED
data/lib/sockd.rb
CHANGED
@@ -1,32 +1,176 @@
|
|
1
|
-
require "
|
2
|
-
require "
|
1
|
+
require "yaml"
|
2
|
+
require "optparse"
|
3
3
|
require "sockd/runner"
|
4
4
|
require "sockd/version"
|
5
5
|
|
6
6
|
module Sockd
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
Runner.define(name, options, &block)
|
11
|
-
end
|
8
|
+
class ParseError < OptionParser::ParseError; end
|
9
|
+
class ConfigFileError < RuntimeError; end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def define(name = nil, options = {}, &block)
|
14
|
+
Runner.define(name = nil, options, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias new define
|
18
|
+
|
19
|
+
def run(name = nil, options = {}, &block)
|
20
|
+
parse define(name, options, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse(runner, argv = ARGV, &block)
|
24
|
+
raise ArgumentError, 'You must provide an instance of Sockd::Runner' unless runner.class <= Runner
|
25
|
+
options = {}
|
26
|
+
parser = optparser(runner.name, options, &block)
|
27
|
+
command, *message = parser.parse(argv)
|
28
|
+
|
29
|
+
if options[:config_save]
|
30
|
+
save_path = options[:config_path] || runner.options[:config_path]
|
31
|
+
raise ParseError, 'no config file path specified, unable to save' unless save_path
|
32
|
+
save_yaml options, save_path
|
33
|
+
|
34
|
+
puts "config saved to: #{path}"
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
|
38
|
+
if options[:config_path]
|
39
|
+
read_yaml options, options[:config_path]
|
40
|
+
elsif runner.options[:config_path] && File.file?(runner.options[:config_path])
|
41
|
+
read_yaml options, runner.options[:config_path]
|
42
|
+
end
|
43
|
+
|
44
|
+
runner.options.merge! options
|
45
|
+
|
46
|
+
case command
|
47
|
+
when nil
|
48
|
+
runner.options[:daemonize] = false
|
49
|
+
runner.start
|
50
|
+
when 'start', 'stop', 'restart'
|
51
|
+
raise ParseError, "invalid arguments for #{command}" unless message.empty?
|
52
|
+
runner.public_send command.to_sym
|
53
|
+
else
|
54
|
+
message.unshift command unless command == 'send'
|
55
|
+
raise ParseError, 'no message provided' if message.empty?
|
56
|
+
puts runner.send message.join(' ')
|
57
|
+
end
|
58
|
+
rescue OptionParser::ParseError => e
|
59
|
+
puts "Error: #{e.message}"
|
60
|
+
puts parser
|
61
|
+
puts ''
|
62
|
+
exit 1
|
63
|
+
rescue ConfigFileError, Runner::ServiceError => e
|
64
|
+
puts "Error: #{e.message}"
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def optparser(name, options)
|
71
|
+
OptionParser.new do |opts|
|
72
|
+
opts.program_name = name
|
73
|
+
opts.summary_width = 25
|
74
|
+
opts.banner = <<-EOF.gsub /^[ ]{8}/, ''
|
75
|
+
|
76
|
+
Usage: #{name} [options] <command> [<message>]
|
77
|
+
|
78
|
+
Commands:
|
79
|
+
#{name} run server without forking
|
80
|
+
#{name} start start as a daemon
|
81
|
+
#{name} stop [-f] stop a running daemon
|
82
|
+
#{name} restart stop, then start the daemon
|
83
|
+
#{name} send <message> send a message to a running daemon
|
84
|
+
#{name} <message> send a message (send command implied)
|
85
|
+
|
86
|
+
Options:
|
87
|
+
EOF
|
88
|
+
|
89
|
+
# allow user to specify custom options
|
90
|
+
yield opts, options if block_given?
|
91
|
+
|
92
|
+
opts.on('-p', '--port PORT', String, 'Listen on TCP port PORT') do |port|
|
93
|
+
options[:port] = port
|
94
|
+
options[:socket] = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
opts.on('-H', '--host HOST', String, 'Listen on HOST') do |host|
|
98
|
+
options[:host] = host
|
99
|
+
options[:socket] = nil
|
100
|
+
end
|
101
|
+
|
102
|
+
opts.on('-s', '--socket PATH', String,
|
103
|
+
'Listen on Unix domain socket PATH (disables TCP support)') do |path|
|
104
|
+
options[:socket] = File.expand_path(path)
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.on('-m', '--mode MODE', OptionParser::OctalInteger,
|
108
|
+
'Set file permissions when using Unix socket') do |mode|
|
109
|
+
options[:mode] = mode
|
110
|
+
end
|
111
|
+
|
112
|
+
opts.on('-P', '--pid PATH', String, 'Where to write the PID file') do |path|
|
113
|
+
options[:pid_path] = File.expand_path(path)
|
114
|
+
end
|
115
|
+
|
116
|
+
opts.on('-l', '--log PATH', String, 'Where to write the log file') do |path|
|
117
|
+
options[:log_path] = File.expand_path(path)
|
118
|
+
end
|
119
|
+
|
120
|
+
opts.on('-u', '--user USER', String,
|
121
|
+
'Assume the identity of USER when running as a daemon') do |user|
|
122
|
+
options[:user] = user
|
123
|
+
end
|
124
|
+
|
125
|
+
opts.on('-g', '--group GROUP', String,
|
126
|
+
'Assume group GROUP when running as a daemon') do |group|
|
127
|
+
options[:group] = group
|
128
|
+
end
|
129
|
+
|
130
|
+
opts.on('-f', '--force',
|
131
|
+
'Force kill if SIGTERM fails when running "stop" command') do
|
132
|
+
options[:force] = true
|
133
|
+
end
|
134
|
+
|
135
|
+
opts.separator ''
|
136
|
+
opts.separator 'Additional Options:'
|
137
|
+
|
138
|
+
opts.on_tail('--config PATH', String,
|
139
|
+
'Load default parameters from YAML file at PATH') do |path|
|
140
|
+
options[:config_path] = File.expand_path(path)
|
141
|
+
end
|
142
|
+
|
143
|
+
opts.on_tail('--save', 'Save current parameters into a config file') do
|
144
|
+
options[:config_save] = true
|
145
|
+
end
|
146
|
+
|
147
|
+
opts.on_tail('-h', '--help', 'Display this usage information') do
|
148
|
+
puts opts
|
149
|
+
puts ''
|
150
|
+
exit
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def read_yaml(options, path)
|
156
|
+
config = YAML.load_file(path).merge!(options)
|
157
|
+
options.replace(config)
|
158
|
+
rescue Errno::EACCES, Errno::EISDIR => e
|
159
|
+
raise ConfigFileError, "unable to read config (#{e.message})"
|
160
|
+
end
|
161
|
+
|
162
|
+
def save_yaml(options, path)
|
163
|
+
options[:mode] = sprintf('0%o', options[:mode]) if options[:mode]
|
164
|
+
options.delete(:config_path)
|
165
|
+
options.delete(:config_save)
|
17
166
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
warn "#{parser}\n"
|
27
|
-
exit
|
28
|
-
rescue SockdError => e
|
29
|
-
warn "Error: #{e.message}"
|
30
|
-
exit
|
167
|
+
FileUtils.mkdir_p(File.dirname(path), mode: 0755)
|
168
|
+
File.open(path, 'w') do |file|
|
169
|
+
file.write options.to_yaml
|
170
|
+
end
|
171
|
+
File.chmod(0644, path)
|
172
|
+
rescue Errno::EACCES, Errno::EISDIR => e
|
173
|
+
raise ConfigFileError, "unable to save config (#{e.message})"
|
174
|
+
end
|
31
175
|
end
|
32
176
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sockd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Greiling
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -53,8 +53,6 @@ files:
|
|
53
53
|
- examples/listd.rb
|
54
54
|
- examples/piglatin.rb
|
55
55
|
- lib/sockd.rb
|
56
|
-
- lib/sockd/errors.rb
|
57
|
-
- lib/sockd/optparse.rb
|
58
56
|
- lib/sockd/runner.rb
|
59
57
|
- lib/sockd/version.rb
|
60
58
|
- sockd.gemspec
|
data/lib/sockd/errors.rb
DELETED
data/lib/sockd/optparse.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
require "fileutils"
|
2
|
-
require "optparse"
|
3
|
-
require "shellwords"
|
4
|
-
require "sockd/errors"
|
5
|
-
|
6
|
-
module Sockd
|
7
|
-
class OptionParser
|
8
|
-
|
9
|
-
attr_accessor :name, :options, :callback
|
10
|
-
|
11
|
-
def initialize(name = nil, defaults = {}, &block)
|
12
|
-
@name = name || File.basename($0)
|
13
|
-
@options = defaults.replace({
|
14
|
-
host: "127.0.0.1",
|
15
|
-
port: 0,
|
16
|
-
socket: false,
|
17
|
-
mode: 0660,
|
18
|
-
daemonize: true,
|
19
|
-
pid_path: "/var/run/#{safe_name}.pid",
|
20
|
-
log_path: false,
|
21
|
-
force: false,
|
22
|
-
user: false,
|
23
|
-
group: false
|
24
|
-
}.merge(defaults))
|
25
|
-
@callback = block if block_given?
|
26
|
-
end
|
27
|
-
|
28
|
-
def safe_name
|
29
|
-
name.gsub(/(^[0-9]*|[^0-9a-z])/i, '')
|
30
|
-
end
|
31
|
-
|
32
|
-
def parser
|
33
|
-
@parser ||= ::OptionParser.new do |opts|
|
34
|
-
opts.summary_width = 25
|
35
|
-
opts.banner = <<-EOF.gsub /^[ ]{8}/, ''
|
36
|
-
Usage: #{name} [options] <command> [<message>]
|
37
|
-
|
38
|
-
Commands:
|
39
|
-
#{name} run server without forking
|
40
|
-
#{name} start start as a daemon
|
41
|
-
#{name} stop [-f] stop a running daemon
|
42
|
-
#{name} restart stop, then start the daemon
|
43
|
-
#{name} send <message> send a message to a running daemon
|
44
|
-
#{name} <message> send a message (send command implied)
|
45
|
-
|
46
|
-
Options:
|
47
|
-
EOF
|
48
|
-
|
49
|
-
instance_exec(opts, &callback) if callback
|
50
|
-
|
51
|
-
opts.on("-p", "--port PORT", String, "Listen on TCP port PORT (default: #{options[:port]})") do |x|
|
52
|
-
options[:port] = x
|
53
|
-
# prefer TCP connection if explicitly setting a port
|
54
|
-
options[:socket] = nil
|
55
|
-
end
|
56
|
-
|
57
|
-
opts.on("-H", "--host HOST", String, "Listen on HOST (default: #{options[:host]})") do |x|
|
58
|
-
options[:host] = x
|
59
|
-
# prefer TCP connection if explicitly setting a host
|
60
|
-
options[:socket] = nil
|
61
|
-
end
|
62
|
-
|
63
|
-
opts.on("-s", "--socket SOCKET", String, "Listen on Unix socket path (disables network support)", "(default: #{options[:socket]})") do |x|
|
64
|
-
options[:socket] = File.expand_path(x)
|
65
|
-
end
|
66
|
-
|
67
|
-
opts.on("-m", "--mode MODE", String, "Set file permissions when using Unix socket", "(default: #{options[:mode]})") do |x|
|
68
|
-
options[:mode] = x
|
69
|
-
end
|
70
|
-
|
71
|
-
opts.on("-P", "--pid FILE", String, "Where to write the PID file", "(default: #{options[:pid_path]})") do |x|
|
72
|
-
options[:pid_path] = File.expand_path(x)
|
73
|
-
end
|
74
|
-
|
75
|
-
opts.on("-l", "--log FILE", String, "Where to write the log file", "(default: #{options[:log_path]})") do |x|
|
76
|
-
options[:log_path] = File.expand_path(x)
|
77
|
-
end
|
78
|
-
|
79
|
-
opts.on("-u", "--user USER", String, "Assume the identity of USER when running as a daemon", "(default: #{options[:user]})") do |x|
|
80
|
-
options[:user] = x
|
81
|
-
end
|
82
|
-
|
83
|
-
opts.on("-g", "--group GROUP", String, "Assume group GROUP when running as a daemon", "(default: #{options[:group]})") do |x|
|
84
|
-
options[:group] = x
|
85
|
-
end
|
86
|
-
|
87
|
-
opts.on("-f", "--force", String, "Force kill if SIGTERM fails when running 'stop' command") do
|
88
|
-
options[:force] = true
|
89
|
-
end
|
90
|
-
|
91
|
-
opts.separator "\n Additional Options:"
|
92
|
-
|
93
|
-
opts.on_tail("-h", "--help", "Display this usage information.") do
|
94
|
-
puts "\n#{opts}\n"
|
95
|
-
exit
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def parse!(argv = nil)
|
101
|
-
argv ||= ARGV.dup
|
102
|
-
argv = Shellwords.shellwords argv if argv.is_a? String
|
103
|
-
|
104
|
-
parser.parse! argv
|
105
|
-
|
106
|
-
if argv.empty?
|
107
|
-
argv.push 'start'
|
108
|
-
options[:daemonize] = false
|
109
|
-
end
|
110
|
-
argv.unshift 'send' unless %w(start stop restart send).include?(argv.first)
|
111
|
-
|
112
|
-
argv
|
113
|
-
rescue ::OptionParser::InvalidOption, ::OptionParser::MissingArgument => e
|
114
|
-
raise OptionParserError.new e
|
115
|
-
end
|
116
|
-
|
117
|
-
def to_s
|
118
|
-
parser.to_s
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|