"yadaemon.rb" is my daemon wrapper class to protect the multiple process invocation.
リビジョン | dfde30b1f5206e919aa28aef23e372dd23e7ec7d (tree) |
---|---|
日時 | 2011-01-24 01:15:15 |
作者 | Yasuhiro ABE <yasundial@user...> |
コミッター | Yasuhiro ABE |
Fixed typos, such as "initializea"
Enhancement "stop" method to use the "stop.txt" file.
Added the "running" method which will work with the "stop.txt" file.
Fixed the @file_perms never be used bug.
Fixed the return code evaluation of the File::chown from zero (ruby1.8) to one (ruby1.9).
Added the "write_file" module method and work to write some files.
@@ -36,7 +36,7 @@ end | ||
36 | 36 | |
37 | 37 | daemon.run do |pid| |
38 | 38 | i = 0 |
39 | - while true | |
39 | + while daemon.running | |
40 | 40 | open(outfile,"w") do |f| |
41 | 41 | f.flock(File::LOCK_EX) |
42 | 42 | f.write(format("%s: %s\n", open(pid).read, i)) |
@@ -15,7 +15,7 @@ daemon = YaDaemon.new(appname,"test.pid","/tmp", opts) ## the "/tmp/#{appname}/ | ||
15 | 15 | outfile = "/tmp/#{appname}/test.log" ## Check this file each five seconds later. |
16 | 16 | daemon.run do |pid| |
17 | 17 | i = 0 |
18 | - while true | |
18 | + while daemon.running | |
19 | 19 | open(outfile,"w") do |f| |
20 | 20 | f.flock(File::LOCK_EX) |
21 | 21 | f.write(format("updated: %d\n", i)) |
@@ -34,7 +34,7 @@ end | ||
34 | 34 | |
35 | 35 | daemon.run do |pid| |
36 | 36 | i = 0 |
37 | - while true | |
37 | + while daemon.running | |
38 | 38 | open(outfile,"w") do |f| |
39 | 39 | f.flock(File::LOCK_EX) |
40 | 40 | f.write(format("%s: %s\n", open(pid).read, i)) |
@@ -39,7 +39,7 @@ | ||
39 | 39 | # {:daemon=>false,:debug=>true}) |
40 | 40 | # daemon.run do |pid| ## pid == /tmp/myappname/myappname.pid |
41 | 41 | # ## please write you code like the following; |
42 | -# while true | |
42 | +# while daemon.running | |
43 | 43 | # puts Time.now |
44 | 44 | # sleep 3 |
45 | 45 | # end |
@@ -93,7 +93,7 @@ | ||
93 | 93 | # |
94 | 94 | # "0755" or "755" will be converted to a octal variable by the 'oct' method. |
95 | 95 | # If you use a numeric variable, you must use octal expression, like 0755. |
96 | -# It means that 755 is wrong expression. | |
96 | +# It means that 755 is wrong expression, but 493 is correct. | |
97 | 97 | # |
98 | 98 | #=File Permissions |
99 | 99 | # |
@@ -105,13 +105,13 @@ | ||
105 | 105 | # If you use :debug=true option, the piddir/appname/"debug.log" file |
106 | 106 | # will be also created by uid:gid, and then chown-ed by euid:egid. |
107 | 107 | # |
108 | -# | @pidpath | | |
109 | -# | @piddir | | | |
110 | -# | pidpdir | appname | pidfile | "debug.log" | | |
111 | -# ---------+---------+---------+---------+-------------+ | |
112 | -# user id | x | <uid>* | <uid>* | @euid= | | |
113 | -# group id | x | - | - | @egid= | | |
114 | -# ---------+---------+---------+---------+-------------+ | |
108 | +# | @pidpath | | | | |
109 | +# | @piddir / | | | | |
110 | +# | pidpdir / appname / pidfile | "debug.log" | "stop.txt" | | |
111 | +# ---------+---------+---------+---------+-------------+------------+ | |
112 | +# user id | x | @euid= | <uid>= | @euid= | @euid* | | |
113 | +# group id | x | - | - | @egid= | @egid= | | |
114 | +# ---------+---------+---------+---------+-------------+------------+ | |
115 | 115 | # (<uid>,<gid> is same as Process::uid, Process::gid) |
116 | 116 | # ('=' means these ownerships will be overwritten) |
117 | 117 | # ('*' means it should be writable by that id) |
@@ -134,20 +134,22 @@ | ||
134 | 134 | # limitations under the License. |
135 | 135 | # |
136 | 136 | # |
137 | - | |
138 | 137 | # It's a utility class to process common tasks. |
139 | 138 | # These methods should be tested by the unit test script. |
139 | +# | |
140 | 140 | module YaDaemonUtils |
141 | - | |
141 | + | |
142 | + ## | |
143 | + ## Note: | |
144 | + ## The following methods having same prefix 'check_' are support methods for the option parser. | |
145 | + ## | |
142 | 146 | def check_boolean(opts, label) |
143 | 147 | (opts.has_key?(label) and (opts[label].kind_of?(FalseClass) or opts[label].kind_of?(TrueClass))) ? opts[label] : false |
144 | 148 | end |
145 | - | |
146 | 149 | def check_eugid(opts, label) |
147 | 150 | label = "uid" if Process::methods.index(label) == nil |
148 | 151 | (Process::uid == 0 and opts.has_key?(label) and opts[label].methods.index(:to_i) != nil) ? opts[label].to_i : Process.method(label).call |
149 | 152 | end |
150 | - | |
151 | 153 | def check_default_perms(opts,label) |
152 | 154 | perm = 0711 |
153 | 155 | if opts.has_key?(label) |
@@ -159,6 +161,25 @@ module YaDaemonUtils | ||
159 | 161 | end |
160 | 162 | perm |
161 | 163 | end |
164 | + | |
165 | + ## It's a wrapper method to write something to the given filepath. | |
166 | + ## args: perms must be fixed num | |
167 | + ## return: true(if success) or false | |
168 | + def write_file(filepath, perms, data) | |
169 | + ret = false | |
170 | + begin | |
171 | + open(filepath, File::RDWR|File::CREAT, perms) do |f| | |
172 | + f.flock(File::LOCK_EX) | |
173 | + f.write(data.to_s) | |
174 | + f.flush | |
175 | + f.truncate(f.pos) | |
176 | + end | |
177 | + ret = true | |
178 | + rescue | |
179 | + ret = false | |
180 | + end | |
181 | + ret | |
182 | + end | |
162 | 183 | end |
163 | 184 | |
164 | 185 | ## It is a simple unix-like daemon class. |
@@ -194,30 +215,51 @@ class YaDaemon | ||
194 | 215 | @egid = check_eugid(opts,:egid) |
195 | 216 | @file_perms = check_default_perms(opts,:perms) |
196 | 217 | |
197 | - ## pidpdir must exist. | |
218 | + ## take care the pidpdir which must exists. | |
198 | 219 | raise "pidpdir, #{pidpdir}, not exist." if not FileTest::exist?(pidpdir) |
199 | - | |
220 | + | |
221 | + ## prepare @piddir and @pidpath | |
200 | 222 | @piddir = File::join([File::expand_path(pidpdir),appname]) |
201 | 223 | raise "cannot mkdir(#{piddir})" if not FileTest::exist?(@piddir) and Dir::mkdir(@piddir) != 0 |
202 | - | |
224 | + ## change ownership of @piddir | |
225 | + stat = File::Stat.new(@piddir) | |
226 | + if stat.uid != @euid | |
227 | + if File::chown(@euid, nil, @piddir) == 1 | |
228 | + logit "initialize: succesfully changed #{@piddir}'s ownership." | |
229 | + else | |
230 | + raise "failed to chown #{@piddir}." | |
231 | + end | |
232 | + end | |
203 | 233 | @pidpath = File::join([@piddir, pidfile]) |
204 | - @debugfile = File::join([@piddir,"debug.log"]) if @debug | |
234 | + | |
235 | + ## prepare the @stopfile | |
236 | + ## used by run/stop methods and delete if existing. | |
237 | + @stopfile = File::join([@piddir, "stop.txt"]) | |
238 | + if FileTest.exist?(@stopfile) | |
239 | + if File::unlink(@stopfile) != 1 | |
240 | + logit "failed to delete the stop file, #{@stopfile}." | |
241 | + raise "failed to delete the stop file, #{@stopfile}." | |
242 | + end | |
243 | + end | |
205 | 244 | |
245 | + ## prepare the @debugfile | |
246 | + @debugfile = File::join([@piddir,"debug.log"]) if @debug | |
206 | 247 | ## change owner,group of @debugfile. |
207 | 248 | if @debug and Process::uid == 0 |
208 | - if not FileTest::exist?(@debugfile) | |
209 | - begin | |
210 | - ## touch @debugfile | |
211 | - open(@debugfile,"w") do |f| f.write() end | |
212 | - rescue | |
213 | - raise "cannot touch debug.log, #{@debugfile}." | |
249 | + if not FileTest::exist?(@debugfile) | |
250 | + if write_file(@debugfile, @file_perms, "") | |
251 | + logit "succesfully create the debug.log file, #{@debugfile}." | |
252 | + else | |
253 | + logit "failed to touch the debug.log file, #{@debugfile}." | |
254 | + raise "failed to touch the debug.log file, #{@debugfile}." | |
214 | 255 | end |
215 | 256 | end |
216 | 257 | stat = File::Stat.new(@debugfile) |
217 | 258 | if stat.uid != @euid or stat.gid != @egid |
218 | - if File::chown(@euid, @egid, @debugfile) == 0 | |
219 | - logit "initializea: succesfully changed #{@debugfile}'s ownership." | |
259 | + if File::chown(@euid, @egid, @debugfile) == 1 | |
260 | + logit "initialize: succesfully changed #{@debugfile}'s ownership." | |
220 | 261 | else |
262 | + logit "failed to chown #{@debugfile}." | |
221 | 263 | raise "failed to chown #{@debugfile}." |
222 | 264 | end |
223 | 265 | end |
@@ -228,12 +270,12 @@ class YaDaemon | ||
228 | 270 | logit "get_pid: called" |
229 | 271 | pid = 0 |
230 | 272 | begin |
231 | - open(@pidpath).each_line do |l| pid = l end | |
273 | + open(@pidpath).each_line do |l| pid = l.to_i end | |
232 | 274 | rescue |
233 | 275 | logit "get_pid: failed to open the pid file, @pidpath." |
234 | 276 | end |
235 | 277 | logit "get_pid: return #{pid}" |
236 | - pid.to_i | |
278 | + pid | |
237 | 279 | end |
238 | 280 | |
239 | 281 | ## If a running process was found and it was not the own process, then return true. |
@@ -251,9 +293,9 @@ class YaDaemon | ||
251 | 293 | logit("check_proc: the pid file exists, but it has own process number. It's harmless, but should be never called.") |
252 | 294 | return ret |
253 | 295 | end |
254 | - ## case 2: check /proc/$pid. (available on limited systems only) | |
296 | + ## case 2a: check /proc/$pid. (available on limited systems only) | |
255 | 297 | ## skipped. |
256 | - ## case 3: using kill -0 method (widely available on unix-like systems) | |
298 | + ## case 2b: using kill -0 method (widely available on unix-like systems) | |
257 | 299 | begin |
258 | 300 | k = Process::kill(0, pid) |
259 | 301 | ret = true if k == 1 |
@@ -265,20 +307,15 @@ class YaDaemon | ||
265 | 307 | ret |
266 | 308 | end |
267 | 309 | |
310 | + def create_stop_file | |
311 | + ret = write_file(@stopfile, @file_perms, "") | |
312 | + logit "create_stop_file: return #{ret}" | |
313 | + ret | |
314 | + end | |
315 | + | |
268 | 316 | ## If there is no running process, then the pid file will be overwritten. |
269 | 317 | def overwrite_pid_file |
270 | - logit "overwrite_pid_file: called" | |
271 | - ret = false | |
272 | - begin | |
273 | - open(@pidpath, "w", 0644) do |f| | |
274 | - f.write(Process::pid.to_s) | |
275 | - f.flush | |
276 | - f.truncate(f.pos) | |
277 | - end | |
278 | - ret = true | |
279 | - rescue | |
280 | - ret = false | |
281 | - end | |
318 | + ret = write_file(@pidpath, @file_perms, Process::pid.to_s) | |
282 | 319 | logit "overwrite_pid_file: return #{ret}" |
283 | 320 | ret |
284 | 321 | end |
@@ -327,6 +364,10 @@ class YaDaemon | ||
327 | 364 | |
328 | 365 | def stop |
329 | 366 | logit "stop: called" |
367 | + | |
368 | + ## overwrite @stopfile | |
369 | + create_stop_file() | |
370 | + | |
330 | 371 | if not check_proc |
331 | 372 | logit "stop: this process has already stopped." |
332 | 373 | return |
@@ -363,4 +404,9 @@ class YaDaemon | ||
363 | 404 | end |
364 | 405 | ret |
365 | 406 | end |
407 | + | |
408 | + def running | |
409 | + not FileTest.exist?(@stopfile) | |
410 | + end | |
411 | + | |
366 | 412 | end |