Skip to content

Instantly share code, notes, and snippets.

@FooBarWidget
Last active Apr 19, 2016
Embed
What would you like to do?
#!/usr/bin/env ruby
# This tool reads from STDIN and forwards all data to a file.
# It reopens the file upon receiving the SIGHUP signal.
require 'fcntl'
class Pipetool
def initialize(input, filename)
@input = input
@filename = filename
@event_pipe = IO.pipe
make_nonblock(@input)
make_nonblock(@event_pipe[0])
make_nonblock(@event_pipe[1])
@input.binmode
@event_pipe[1].sync = true
reopen_file
trap("HUP", &method(:on_sighup))
debug "Event pipe on FDs #{@event_pipe[0].fileno}, #{@event_pipe[1].fileno}"
end
def main
debug "Pipetool started on PID #{Process.pid}"
done = false
while !done
ios = select([@input, @event_pipe[0]])[0]
if ios[0] == @event_pipe[0]
debug "Reopening #{@filename}"
drain_io(@event_pipe[0])
reopen_file
else
done = forward_block
end
end
rescue SignalException => e
if !is_exit_signal?(e)
raise
end
end
private
def make_nonblock(io)
flags = io.fcntl(Fcntl::F_GETFL)
io.fcntl(Fcntl::F_SETFL, flags | Fcntl::O_NONBLOCK)
end
def on_sighup(signo)
debug "SIGHUP received"
@event_pipe[1].write('x')
end
def drain_io(io)
while true
begin
io.read_nonblock(1024 * 16)
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINTR
break
end
end
end
def reopen_file
@output.close if @output
@output = File.open(@filename, "ab")
@output.sync = true
end
def forward_block
begin
buf = @input.read_nonblock(1024 * 32)
rescue EOFError
return true
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINTR
return false
end
@output.write(buf)
false
end
def is_exit_signal?(e)
e.signo == Signal.list['TERM'] || e.signo == Signal.list['INT']
end
def debug(message)
#STDERR.puts(message)
end
end
abort "Usage: pipetool <FILENAME>" if !ARGV[0]
Pipetool.new(STDIN, ARGV[0]).main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment