ruby-watchcat-pure 1.0.0 → 1.1.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.
- data/README +2 -0
- data/lib/watchcat.rb +151 -41
- metadata +2 -2
data/README
CHANGED
@@ -18,6 +18,8 @@ Ruby/Watchcatd allows a Ruby application to register itself with watchcatd.
|
|
18
18
|
Ruby/Watchcatd was tested with Ruby versions >= 1.8.4 and requires watchcatd
|
19
19
|
version 1.1 and libwcat version 1.0 to be installed (see References below).
|
20
20
|
|
21
|
+
For FreeBSD support, you need at least watchcatd 1.2 (and libwcat 1.1 if you
|
22
|
+
are using the C extension).
|
21
23
|
|
22
24
|
== Installation
|
23
25
|
|
data/lib/watchcat.rb
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
14
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
15
|
#
|
16
|
-
# $Id: watchcat.rb
|
16
|
+
# $Id: watchcat.rb 29 2008-08-29 18:52:47Z andre $
|
17
17
|
#++
|
18
18
|
|
19
19
|
# Pure-ruby version of libwcat.
|
@@ -30,7 +30,7 @@ require 'socket'
|
|
30
30
|
#
|
31
31
|
class Watchcat
|
32
32
|
DEFAULT_TIMEOUT = 60
|
33
|
-
DEFAULT_DEVICE = '/
|
33
|
+
DEFAULT_DEVICE = '/var/run/watchcat.socket'
|
34
34
|
DEFAULT_SIGNAL = Signal.list['KILL']
|
35
35
|
|
36
36
|
# Create a new Watchcat object. The parameter hash may have the following
|
@@ -46,8 +46,8 @@ class Watchcat
|
|
46
46
|
# Should be a string which is added to the log generated by watchcatd
|
47
47
|
# when it signals a process. (default: nil)
|
48
48
|
# +device+::
|
49
|
-
# The watchcat device. (default: +/
|
50
|
-
# purposes.
|
49
|
+
# The watchcat device. (default: +/var/run/watchcat.socket+). Use for
|
50
|
+
# debugging purposes.
|
51
51
|
#
|
52
52
|
# If a block is given, the Watchcat object will be yielded and automatically
|
53
53
|
# closed on block termination.
|
@@ -60,46 +60,25 @@ class Watchcat
|
|
60
60
|
raise ArgumentError, 'timeout must be an integer'
|
61
61
|
end
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
when String
|
67
|
-
signal = Signal.list[args[:signal].sub(/^SIG/, '')]
|
68
|
-
raise ArgumentError, "invalid signal name" if signal.nil?
|
69
|
-
when Fixnum
|
70
|
-
signal = args[:signal]
|
71
|
-
else
|
72
|
-
raise ArgumentError, "signal must be an integer or a string"
|
73
|
-
end
|
74
|
-
|
75
|
-
@sock = UNIXSocket.new(device)
|
76
|
-
if Fcntl.const_defined? :F_SETFD
|
77
|
-
@sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
78
|
-
end
|
79
|
-
|
80
|
-
msg = "version: 1\ntimeout: #{timeout}\nsignal: #{signal}"
|
81
|
-
if info.nil?
|
82
|
-
msg << "\n\n"
|
83
|
-
else
|
84
|
-
info.gsub!(/\n/, '_')
|
85
|
-
msg << "\ninfo: #{info}\n\n"
|
86
|
-
end
|
63
|
+
signal = signal_number(args[:signal])
|
64
|
+
@sock = create_socket(device)
|
65
|
+
msg = build_message(timeout, signal, info)
|
87
66
|
|
88
67
|
safe_write(@sock, msg)
|
89
|
-
|
90
|
-
if block_given?
|
91
|
-
begin
|
92
|
-
yield(self)
|
93
|
-
ensure
|
94
|
-
@sock.close
|
95
|
-
end
|
96
|
-
end
|
97
|
-
return self
|
98
|
-
else
|
68
|
+
unless safe_read(@sock, 256) == "ok\n"
|
99
69
|
@sock.close
|
100
|
-
# Probably not the best error, but it matches
|
70
|
+
# Probably not the best error, but it matches libwcat.
|
101
71
|
raise Errno::EPERM
|
102
72
|
end
|
73
|
+
|
74
|
+
if block_given?
|
75
|
+
begin
|
76
|
+
yield(self)
|
77
|
+
ensure
|
78
|
+
@sock.close
|
79
|
+
end
|
80
|
+
end
|
81
|
+
return self
|
103
82
|
end
|
104
83
|
|
105
84
|
# Send a heartbeat to watchcatd, telling it we're still alive.
|
@@ -120,14 +99,52 @@ class Watchcat
|
|
120
99
|
|
121
100
|
private
|
122
101
|
|
102
|
+
def signal_number(value)
|
103
|
+
case value
|
104
|
+
when nil
|
105
|
+
signal = DEFAULT_SIGNAL
|
106
|
+
when String
|
107
|
+
signal = Signal.list[args[:signal].sub(/^SIG/, '')]
|
108
|
+
raise ArgumentError, "invalid signal name" if signal.nil?
|
109
|
+
when Fixnum
|
110
|
+
signal = args[:signal]
|
111
|
+
else
|
112
|
+
raise ArgumentError, "signal must be an integer or a string"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_socket(device)
|
117
|
+
sock = UNIXSocket.new(device)
|
118
|
+
if Fcntl.const_defined? :F_SETFD
|
119
|
+
sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
120
|
+
end
|
121
|
+
return sock
|
122
|
+
end
|
123
|
+
|
124
|
+
def build_message(timeout, signal, info)
|
125
|
+
msg = "version: 1\ntimeout: #{timeout}\nsignal: #{signal}"
|
126
|
+
if info.nil?
|
127
|
+
msg << "\n\n"
|
128
|
+
else
|
129
|
+
info.gsub!(/\n/, '_')
|
130
|
+
msg << "\ninfo: #{info}\n\n"
|
131
|
+
end
|
132
|
+
return msg
|
133
|
+
end
|
134
|
+
|
123
135
|
def safe_write(fd, buf)
|
124
136
|
act = Signal.trap('PIPE', 'IGN')
|
125
137
|
begin
|
126
|
-
|
138
|
+
if RUBY_PLATFORM =~ /freebsd/i
|
139
|
+
FreeBSD.sendmsg(fd, " #{buf}") # XXX prepend an extra byte
|
140
|
+
else
|
141
|
+
fd.syswrite(buf)
|
142
|
+
end
|
127
143
|
rescue Errno::EINTR
|
128
144
|
retry
|
145
|
+
ensure
|
146
|
+
Signal.trap('PIPE', act)
|
129
147
|
end
|
130
|
-
Signal.trap('PIPE', act)
|
131
148
|
end
|
132
149
|
|
133
150
|
def safe_read(fd, len)
|
@@ -140,3 +157,96 @@ private
|
|
140
157
|
return buf
|
141
158
|
end
|
142
159
|
end
|
160
|
+
|
161
|
+
module FreeBSD # :nodoc:
|
162
|
+
extend(self)
|
163
|
+
|
164
|
+
INT_SIZE = [0].pack("i_").size
|
165
|
+
INT32_SIZE = 4
|
166
|
+
SHORT_SIZE = [0].pack("s_").size
|
167
|
+
CMGROUP_MAX = 16
|
168
|
+
ALIGNBYTES = [0].pack("L_").size - 1
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def align(p, alignbytes = ALIGNBYTES)
|
173
|
+
(p + alignbytes) & ~alignbytes
|
174
|
+
end
|
175
|
+
|
176
|
+
def sizeof(p)
|
177
|
+
align(p, 3)
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# This code depends on structs cmsghdr and cmsgcred being as shown below.
|
182
|
+
# It also depends on sendmsg(2) being syscall number 28 and on the
|
183
|
+
# SOL_SOCKET and SCM_CREDS macros having the same values as the constants
|
184
|
+
# defined below.
|
185
|
+
#
|
186
|
+
# struct cmsghdr {
|
187
|
+
# socklen_t cmsg_len; /* __uint32_t */
|
188
|
+
# int cmsg_level; /* int */
|
189
|
+
# int cmsg_type; /* int */
|
190
|
+
# };
|
191
|
+
#
|
192
|
+
# struct cmsgcred {
|
193
|
+
# pid_t cmcred_pid; /* __int32_t */
|
194
|
+
# uid_t cmcred_uid; /* __uint32_t */
|
195
|
+
# uid_t cmcred_euid; /* __uint32_t */
|
196
|
+
# gid_t cmcred_gid; /* __uint32_t */
|
197
|
+
# short cmcred_ngroups; /* short */
|
198
|
+
# gid_t cmcred_groups[CMGROUP_MAX]; /* __uint32_t * 16 */
|
199
|
+
# };
|
200
|
+
#
|
201
|
+
|
202
|
+
SYS_SENDMSG = 28
|
203
|
+
SOL_SOCKET = 0xffff
|
204
|
+
SCM_CREDS = 0x03
|
205
|
+
|
206
|
+
CMSGCRED_SIZE = sizeof(4*INT_SIZE + SHORT_SIZE + CMGROUP_MAX * INT32_SIZE)
|
207
|
+
CMSGHDR_SIZE = sizeof(INT32_SIZE + 2 * INT_SIZE)
|
208
|
+
|
209
|
+
public
|
210
|
+
|
211
|
+
def sendmsg(fd, buf)
|
212
|
+
iov = [buf, buf.length].pack("pL_")
|
213
|
+
|
214
|
+
cmsg_space = cmsg_space(CMSGCRED_SIZE)
|
215
|
+
cmsg_data_len = cmsg_space - INT32_SIZE - 2*INT_SIZE
|
216
|
+
|
217
|
+
cmsghdr = ([
|
218
|
+
cmsg_len(CMSGCRED_SIZE), # cmsg_len
|
219
|
+
SOL_SOCKET, # cmsg_level
|
220
|
+
SCM_CREDS # cmsg_type
|
221
|
+
] + [0] * cmsg_data_len).pack("I_i_i_C#{cmsg_data_len}")
|
222
|
+
|
223
|
+
msg_control_ptr = pointer(cmsghdr)
|
224
|
+
msg_controllen = cmsg_space
|
225
|
+
|
226
|
+
msghdr = [
|
227
|
+
0, # msg_name
|
228
|
+
0, # msg_namelen
|
229
|
+
pointer(iov), # msg_iov
|
230
|
+
1, # msg_iovlen
|
231
|
+
pointer(cmsghdr), # msg_control
|
232
|
+
cmsg_space, # msg_controllen
|
233
|
+
0 # msg_flags
|
234
|
+
].pack("L_L_L_L_L_L_L_")
|
235
|
+
|
236
|
+
syscall(SYS_SENDMSG, fd.fileno, pointer(msghdr), 0)
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
def pointer(buf)
|
242
|
+
[buf].pack("P").unpack("L_").first
|
243
|
+
end
|
244
|
+
|
245
|
+
def cmsg_len(l)
|
246
|
+
align(CMSGHDR_SIZE) + l
|
247
|
+
end
|
248
|
+
|
249
|
+
def cmsg_space(l)
|
250
|
+
align(CMSGHDR_SIZE) + align(l)
|
251
|
+
end
|
252
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-watchcat-pure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andre Nathan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-08-
|
12
|
+
date: 2008-08-29 00:00:00 -03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|