Unicorn::Util.tmpio => Unicorn::TmpIO.new
[unicorn.git] / lib / unicorn / util.rb
blob8ebdf059321b97ae9a99ba6c522256685c1cda55
1 # -*- encoding: binary -*-
3 require 'fcntl'
5 module Unicorn
7   module Util
8     class << self
10       def is_log?(fp)
11         append_flags = File::WRONLY | File::APPEND
13         ! fp.closed? &&
14           fp.sync &&
15           fp.path[0] == ?/ &&
16           (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags
17         rescue IOError, Errno::EBADF
18           false
19       end
21       def chown_logs(uid, gid)
22         ObjectSpace.each_object(File) do |fp|
23           fp.chown(uid, gid) if is_log?(fp)
24         end
25       end
27       # This reopens ALL logfiles in the process that have been rotated
28       # using logrotate(8) (without copytruncate) or similar tools.
29       # A +File+ object is considered for reopening if it is:
30       #   1) opened with the O_APPEND and O_WRONLY flags
31       #   2) opened with an absolute path (starts with "/")
32       #   3) the current open file handle does not match its original open path
33       #   4) unbuffered (as far as userspace buffering goes, not O_SYNC)
34       # Returns the number of files reopened
35       def reopen_logs
36         to_reopen = []
37         nr = 0
38         ObjectSpace.each_object(File) { |fp| is_log?(fp) and to_reopen << fp }
40         to_reopen.each do |fp|
41           orig_st = begin
42             fp.stat
43           rescue IOError, Errno::EBADF
44             next
45           end
47           begin
48             b = File.stat(fp.path)
49             next if orig_st.ino == b.ino && orig_st.dev == b.dev
50           rescue Errno::ENOENT
51           end
53           begin
54             File.open(fp.path, 'a') { |tmpfp| fp.reopen(tmpfp) }
55             fp.sync = true
56             new_st = fp.stat
58             # this should only happen in the master:
59             if orig_st.uid != new_st.uid || orig_st.gid != new_st.gid
60               fp.chown(orig_st.uid, orig_st.gid)
61             end
63             nr += 1
64           rescue IOError, Errno::EBADF
65             # not much we can do...
66           end
67         end
69         nr
70       end
71     end
72   end
73 end